From b50ab13974adf6f16d72f172f0cf768a44c161da Mon Sep 17 00:00:00 2001 From: Mavridis Philippe Date: Fri, 6 Jan 2023 02:24:35 +0200 Subject: [PATCH] Kxkb: Improve Xkb option detection 1. Prefer XML files for Xkb options, as on some systems they have the a fuller set of options with descriptions than plain Xkb rules files. 2. Various hacks to improve descriptions of newer Xkb options Signed-off-by: Mavridis Philippe --- kxkb/x11helper.cpp | 112 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 22 deletions(-) diff --git a/kxkb/x11helper.cpp b/kxkb/x11helper.cpp index 1c8db4a4a..2663bf4d4 100644 --- a/kxkb/x11helper.cpp +++ b/kxkb/x11helper.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -119,13 +120,12 @@ X11Helper::findXkbRulesFile(TQString x11Dir, Display *dpy) } } } - + return rulesFile; } RulesInfo* -X11Helper::loadRules(const TQString& file, bool layoutsOnly) -{ +X11Helper::loadRules(const TQString& file, bool layoutsOnly) { XkbRF_RulesPtr xkbRules = XkbRF_Load(TQFile::encodeName(file).data(), "", true, true); if (xkbRules == NULL) { @@ -151,32 +151,100 @@ X11Helper::loadRules(const TQString& file, bool layoutsOnly) XkbRF_Free(xkbRules, true); return rulesInfo; } - + for (int i = 0; i < xkbRules->models.num_desc; ++i) rulesInfo->models.replace(xkbRules->models.desc[i].name, tqstrdup( xkbRules->models.desc[i].desc ) ); - for (int i = 0; i < xkbRules->options.num_desc; ++i) - rulesInfo->options.replace(xkbRules->options.desc[i].name, tqstrdup( xkbRules->options.desc[i].desc ) ); - XkbRF_Free(xkbRules, true); + // Prefer XML file for Xkb options + if (TQFile(file + ".xml").exists()) { + XkbRF_Free(xkbRules, true); + + TQDomDocument xmlrules("xkbrules"); + TQFile xmlfile(file + ".xml"); + if (!xmlfile.open(IO_ReadOnly)) { + return NULL; + } + if (!xmlrules.setContent(&xmlfile)) { + xmlfile.close(); + return NULL; + } + xmlfile.close(); + + TQDomElement options = xmlrules.documentElement().namedItem("optionList").toElement(); + TQDomNode optGroupNode = options.firstChild(); + while (!optGroupNode.isNull()) { + TQDomElement optGroupElem = optGroupNode.toElement(); + if (optGroupElem.tagName() == "group") { + TQDomNode optNode = optGroupElem.firstChild(); + while (!optNode.isNull()) { + TQDomElement optElem = optNode.toElement(); + if (!optElem.isNull()) { + // This might be either a configItem (group) or an option tag + // If it is an option tag, it contains a configItem that describes + // the option + if (optElem.tagName() == "option") { + optElem = optElem.namedItem("configItem").toElement(); + } + + TQString optName = optElem.namedItem("name").toElement().text(); + TQString optDesc = optElem.namedItem("description").toElement().text(); + if (optDesc.isEmpty()) { + optDesc = optName; + } + // Items from these 'meta' groups fall into other groups + // Admittedly not the best way to handle this + if (optName == "currencysign" || optName == "compat") break; + + // HACK this should be called "compose" or else the code breaks + if (optName == "Compose key") optName = "compose"; + + rulesInfo->options.replace(optName.ascii(), tqstrdup(optDesc.ascii())); + } + optNode = optNode.nextSibling(); + } + } + optGroupNode = optGroupNode.nextSibling(); + } + } + else { + for (int i = 0; i < xkbRules->options.num_desc; ++i) + rulesInfo->options.replace(xkbRules->options.desc[i].name, tqstrdup( xkbRules->options.desc[i].desc ) ); + + XkbRF_Free(xkbRules, true); + + // workaround for empty 'compose' options group description + if( rulesInfo->options.find("compose:menu") && !rulesInfo->options.find("compose") ) { + rulesInfo->options.replace("compose", "Compose Key Position"); + } + } -// workaround for empty 'compose' options group description - if( rulesInfo->options.find("compose:menu") && !rulesInfo->options.find("compose") ) { - rulesInfo->options.replace("compose", "Compose Key Position"); - } for(TQDictIterator it(rulesInfo->options) ; it.current() != NULL; ++it ) { - TQString option(it.currentKey()); - int columnPos = option.find(":"); - - if( columnPos != -1 ) { - TQString group = option.mid(0, columnPos); - if( rulesInfo->options.find(group) == NULL ) { - rulesInfo->options.replace(group, group.latin1()); - kdDebug() << "Added missing option group: " << group << endl; - } - } + // HACK 2023/06/01 some descriptions in xkb rule files have "< >" in place + // of an actual key name, both in *.lst and *.xml files + TQString descFix = TQString::null; + if (it.currentKey().contains("lsgt_switch")) { + descFix = TQString(it.current()).replace("< >", "LSGT"); + } + else if (it.currentKey().startsWith("compose:102")) { + descFix = TQString(it.current()).replace("< >", "102"); + } + if (!descFix.isNull()) { + rulesInfo->options.replace(it.currentKey(), tqstrdup(descFix.ascii())); + } + + // Add missing option groups + TQString option(it.currentKey()); + int columnPos = option.find(":"); + + if( columnPos != -1 ) { + TQString group = option.mid(0, columnPos); + if( rulesInfo->options.find(group) == NULL ) { + rulesInfo->options.replace(group, group.latin1()); + kdDebug() << "Added missing option group: " << group << endl; + } + } } - // // workaround for empty misc options group description in XFree86 4.4.0 // if( rulesInfo->options.find("numpad:microsoft") && !rulesInfo->options.find("misc") ) { // rulesInfo->options.replace("misc", "Miscellaneous compatibility options" );