Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / apps / konsole / src / KeyboardTranslator.cpp
blobd286eb5c61ec95591a19878dd47f20731992af59
1 /*
2 This source file is part of Konsole, a terminal emulator.
4 Copyright (C) 2007 by Robert Knight <robertknight@gmail.com>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
22 // Own
23 #include "KeyboardTranslator.h"
25 // System
26 #include <ctype.h>
27 #include <stdio.h>
29 // Qt
30 #include <QtCore/QBuffer>
31 #include <KDebug>
32 #include <QtCore/QFile>
33 #include <QtCore/QFileInfo>
34 #include <QtCore/QTextStream>
35 #include <QtGui/QKeySequence>
37 // KDE
38 #include <KDebug>
39 #include <KLocale>
40 #include <KStandardDirs>
42 using namespace Konsole;
45 const char* KeyboardTranslatorManager::defaultTranslatorText =
46 #include <DefaultTranslatorText.h>
49 KeyboardTranslatorManager::KeyboardTranslatorManager()
50 : _haveLoadedAll(false)
53 KeyboardTranslatorManager::~KeyboardTranslatorManager()
55 qDeleteAll(_translators.values());
57 QString KeyboardTranslatorManager::findTranslatorPath(const QString& name)
59 return KGlobal::dirs()->findResource("data","konsole/"+name+".keytab");
61 void KeyboardTranslatorManager::findTranslators()
63 QStringList list = KGlobal::dirs()->findAllResources("data",
64 "konsole/*.keytab",
65 KStandardDirs::NoDuplicates);
67 // add the name of each translator to the list and associated
68 // the name with a null pointer to indicate that the translator
69 // has not yet been loaded from disk
70 QStringListIterator listIter(list);
71 while (listIter.hasNext())
73 QString translatorPath = listIter.next();
75 QString name = QFileInfo(translatorPath).baseName();
77 if ( !_translators.contains(name) )
78 _translators.insert(name,0);
81 _haveLoadedAll = true;
84 const KeyboardTranslator* KeyboardTranslatorManager::findTranslator(const QString& name)
86 if ( name.isEmpty() )
87 return defaultTranslator();
89 if ( _translators.contains(name) && _translators[name] != 0 )
90 return _translators[name];
92 KeyboardTranslator* translator = loadTranslator(name);
94 if ( translator != 0 )
95 _translators[name] = translator;
96 else if ( !name.isEmpty() )
97 kWarning() << "Unable to load translator" << name;
99 return translator;
102 bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator* translator)
104 const QString path = KGlobal::dirs()->saveLocation("data","konsole/")+translator->name()
105 +".keytab";
107 kDebug() << "Saving translator to" << path;
109 QFile destination(path);
111 if (!destination.open(QIODevice::WriteOnly | QIODevice::Text))
113 kWarning() << "Unable to save keyboard translation:"
114 << destination.errorString();
116 return false;
120 KeyboardTranslatorWriter writer(&destination);
121 writer.writeHeader(translator->description());
123 QListIterator<KeyboardTranslator::Entry> iter(translator->entries());
124 while ( iter.hasNext() )
125 writer.writeEntry(iter.next());
128 destination.close();
130 return true;
133 KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(const QString& name)
135 const QString& path = findTranslatorPath(name);
137 QFile source(path);
138 if (name.isEmpty() || !source.open(QIODevice::ReadOnly | QIODevice::Text))
139 return 0;
141 return loadTranslator(&source,name);
144 const KeyboardTranslator* KeyboardTranslatorManager::defaultTranslator()
146 kDebug() << "Loading default translator from text" << defaultTranslatorText;
147 QBuffer textBuffer;
148 textBuffer.setData(defaultTranslatorText,strlen(defaultTranslatorText));
149 return loadTranslator(&textBuffer,"fallback");
152 KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(QIODevice* source,const QString& name)
154 KeyboardTranslator* translator = new KeyboardTranslator(name);
155 KeyboardTranslatorReader reader(source);
156 translator->setDescription( reader.description() );
157 while ( reader.hasNextEntry() )
158 translator->addEntry(reader.nextEntry());
160 source->close();
162 if ( !reader.parseError() )
164 return translator;
166 else
168 delete translator;
169 return 0;
173 KeyboardTranslatorWriter::KeyboardTranslatorWriter(QIODevice* destination)
174 : _destination(destination)
176 Q_ASSERT( destination && destination->isWritable() );
178 _writer = new QTextStream(_destination);
180 KeyboardTranslatorWriter::~KeyboardTranslatorWriter()
182 delete _writer;
184 void KeyboardTranslatorWriter::writeHeader( const QString& description )
186 *_writer << "keyboard \"" << description << '\"' << '\n';
188 void KeyboardTranslatorWriter::writeEntry( const KeyboardTranslator::Entry& entry )
190 QString result;
192 if ( entry.command() != KeyboardTranslator::NoCommand )
193 result = entry.resultToString();
194 else
195 result = '\"' + entry.resultToString() + '\"';
197 *_writer << "key " << entry.conditionToString() << " : " << result << '\n';
201 // each line of the keyboard translation file is one of:
203 // - keyboard "name"
204 // - key KeySequence : "characters"
205 // - key KeySequence : CommandName
207 // KeySequence begins with the name of the key ( taken from the Qt::Key enum )
208 // and is followed by the keyboard modifiers and state flags ( with + or - in front
209 // of each modifier or flag to indicate whether it is required ). All keyboard modifiers
210 // and flags are optional, if a particular modifier or state is not specified it is
211 // assumed not to be a part of the sequence. The key sequence may contain whitespace
213 // eg: "key Up+Shift : scrollLineUp"
214 // "key Next-Shift : "\E[6~"
216 // (lines containing only whitespace are ignored, parseLine assumes that comments have
217 // already been removed)
220 KeyboardTranslatorReader::KeyboardTranslatorReader( QIODevice* source )
221 : _source(source)
222 , _hasNext(false)
224 // read input until we find the description
225 while ( _description.isEmpty() && !source->atEnd() )
227 const QList<Token>& tokens = tokenize( QString(source->readLine()) );
229 if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword )
231 _description = i18n(tokens[1].text.toUtf8());
235 readNext();
237 void KeyboardTranslatorReader::readNext()
239 // find next entry
240 while ( !_source->atEnd() )
242 const QList<Token>& tokens = tokenize( QString(_source->readLine()) );
243 if ( !tokens.isEmpty() && tokens.first().type == Token::KeyKeyword )
245 KeyboardTranslator::States flags = KeyboardTranslator::NoState;
246 KeyboardTranslator::States flagMask = KeyboardTranslator::NoState;
247 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
248 Qt::KeyboardModifiers modifierMask = Qt::NoModifier;
250 int keyCode = Qt::Key_unknown;
252 decodeSequence(tokens[1].text.toLower(),
253 keyCode,
254 modifiers,
255 modifierMask,
256 flags,
257 flagMask);
259 KeyboardTranslator::Command command = KeyboardTranslator::NoCommand;
260 QByteArray text;
262 // get text or command
263 if ( tokens[2].type == Token::OutputText )
265 text = tokens[2].text.toLocal8Bit();
267 else if ( tokens[2].type == Token::Command )
269 // identify command
270 if (!parseAsCommand(tokens[2].text,command))
271 kWarning() << "Command" << tokens[2].text << "not understood.";
274 KeyboardTranslator::Entry newEntry;
275 newEntry.setKeyCode( keyCode );
276 newEntry.setState( flags );
277 newEntry.setStateMask( flagMask );
278 newEntry.setModifiers( modifiers );
279 newEntry.setModifierMask( modifierMask );
280 newEntry.setText( text );
281 newEntry.setCommand( command );
283 _nextEntry = newEntry;
285 _hasNext = true;
287 return;
291 _hasNext = false;
294 bool KeyboardTranslatorReader::parseAsCommand(const QString& text,KeyboardTranslator::Command& command)
296 if ( text.compare("erase",Qt::CaseInsensitive) == 0 )
297 command = KeyboardTranslator::EraseCommand;
298 else if ( text.compare("scrollpageup",Qt::CaseInsensitive) == 0 )
299 command = KeyboardTranslator::ScrollPageUpCommand;
300 else if ( text.compare("scrollpagedown",Qt::CaseInsensitive) == 0 )
301 command = KeyboardTranslator::ScrollPageDownCommand;
302 else if ( text.compare("scrolllineup",Qt::CaseInsensitive) == 0 )
303 command = KeyboardTranslator::ScrollLineUpCommand;
304 else if ( text.compare("scrolllinedown",Qt::CaseInsensitive) == 0 )
305 command = KeyboardTranslator::ScrollLineDownCommand;
306 else if ( text.compare("scrolllock",Qt::CaseInsensitive) == 0 )
307 command = KeyboardTranslator::ScrollLockCommand;
308 else
309 return false;
311 return true;
314 bool KeyboardTranslatorReader::decodeSequence(const QString& text,
315 int& keyCode,
316 Qt::KeyboardModifiers& modifiers,
317 Qt::KeyboardModifiers& modifierMask,
318 KeyboardTranslator::States& flags,
319 KeyboardTranslator::States& flagMask)
321 bool isWanted = true;
322 bool endOfItem = false;
323 QString buffer;
325 Qt::KeyboardModifiers tempModifiers = modifiers;
326 Qt::KeyboardModifiers tempModifierMask = modifierMask;
327 KeyboardTranslator::States tempFlags = flags;
328 KeyboardTranslator::States tempFlagMask = flagMask;
330 for ( int i = 0 ; i < text.count() ; i++ )
332 const QChar& ch = text[i];
333 bool isLastLetter = ( i == text.count()-1 );
335 endOfItem = true;
336 if ( ch.isLetterOrNumber() )
338 endOfItem = false;
339 buffer.append(ch);
342 if ( (endOfItem || isLastLetter) && !buffer.isEmpty() )
344 Qt::KeyboardModifier itemModifier = Qt::NoModifier;
345 int itemKeyCode = 0;
346 KeyboardTranslator::State itemFlag = KeyboardTranslator::NoState;
348 if ( parseAsModifier(buffer,itemModifier) )
350 tempModifierMask |= itemModifier;
352 if ( isWanted )
353 tempModifiers |= itemModifier;
355 else if ( parseAsStateFlag(buffer,itemFlag) )
357 tempFlagMask |= itemFlag;
359 if ( isWanted )
360 tempFlags |= itemFlag;
362 else if ( parseAsKeyCode(buffer,itemKeyCode) )
363 keyCode = itemKeyCode;
364 else
365 kDebug() << "Unable to parse key binding item:" << buffer;
367 buffer.clear();
370 // check if this is a wanted / not-wanted flag and update the
371 // state ready for the next item
372 if ( ch == '+' )
373 isWanted = true;
374 else if ( ch == '-' )
375 isWanted = false;
378 modifiers = tempModifiers;
379 modifierMask = tempModifierMask;
380 flags = tempFlags;
381 flagMask = tempFlagMask;
383 return true;
386 bool KeyboardTranslatorReader::parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier)
388 if ( item == "shift" )
389 modifier = Qt::ShiftModifier;
390 else if ( item == "ctrl" || item == "control" )
391 modifier = Qt::ControlModifier;
392 else if ( item == "alt" )
393 modifier = Qt::AltModifier;
394 else if ( item == "meta" )
395 modifier = Qt::MetaModifier;
396 else if ( item == "keypad" )
397 modifier = Qt::KeypadModifier;
398 else
399 return false;
401 return true;
403 bool KeyboardTranslatorReader::parseAsStateFlag(const QString& item , KeyboardTranslator::State& flag)
405 if ( item == "appcukeys" )
406 flag = KeyboardTranslator::CursorKeysState;
407 else if ( item == "ansi" )
408 flag = KeyboardTranslator::AnsiState;
409 else if ( item == "newline" )
410 flag = KeyboardTranslator::NewLineState;
411 else if ( item == "appscreen" )
412 flag = KeyboardTranslator::AlternateScreenState;
413 else if ( item == "anymod" )
414 flag = KeyboardTranslator::AnyModifierState;
415 else
416 return false;
418 return true;
420 bool KeyboardTranslatorReader::parseAsKeyCode(const QString& item , int& keyCode)
422 QKeySequence sequence = QKeySequence::fromString(item);
423 if ( !sequence.isEmpty() )
425 keyCode = sequence[0];
427 if ( sequence.count() > 1 )
429 kDebug() << "Unhandled key codes in sequence: " << item;
432 // additional cases implemented for backwards compatibility with KDE 3
433 else if ( item == "prior" )
434 keyCode = Qt::Key_PageUp;
435 else if ( item == "next" )
436 keyCode = Qt::Key_PageDown;
437 else
438 return false;
440 return true;
443 QString KeyboardTranslatorReader::description() const
445 return _description;
447 bool KeyboardTranslatorReader::hasNextEntry()
449 return _hasNext;
451 KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& condition ,
452 const QString& result )
454 QString entryString("keyboard \"temporary\"\nkey ");
455 entryString.append(condition);
456 entryString.append(" : ");
458 // if 'result' is the name of a command then the entry result will be that command,
459 // otherwise the result will be treated as a string to echo when the key sequence
460 // specified by 'condition' is pressed
461 KeyboardTranslator::Command command;
462 if (parseAsCommand(result,command))
463 entryString.append(result);
464 else
465 entryString.append('\"' + result + '\"');
467 QByteArray array = entryString.toUtf8();
469 KeyboardTranslator::Entry entry;
471 QBuffer buffer(&array);
472 buffer.open(QIODevice::ReadOnly);
473 KeyboardTranslatorReader reader(&buffer);
475 if ( reader.hasNextEntry() )
476 entry = reader.nextEntry();
478 return entry;
481 KeyboardTranslator::Entry KeyboardTranslatorReader::nextEntry()
483 Q_ASSERT( _hasNext );
486 KeyboardTranslator::Entry entry = _nextEntry;
488 readNext();
490 return entry;
492 bool KeyboardTranslatorReader::parseError()
494 return false;
496 QList<KeyboardTranslatorReader::Token> KeyboardTranslatorReader::tokenize(const QString& line)
498 QString text = line.simplified();
500 // comment line: # comment
501 static QRegExp comment("\\#.*");
502 // title line: keyboard "title"
503 static QRegExp title("keyboard\\s+\"(.*)\"");
504 // key line: key KeySequence : "output"
505 // key line: key KeySequence : command
506 static QRegExp key("key\\s+([\\w\\+\\s\\-]+)\\s*:\\s*(\"(.*)\"|\\w+)");
508 QList<Token> list;
510 if ( text.isEmpty() || comment.exactMatch(text) )
512 return list;
515 if ( title.exactMatch(text) )
517 Token titleToken = { Token::TitleKeyword , QString() };
518 Token textToken = { Token::TitleText , title.capturedTexts()[1] };
520 list << titleToken << textToken;
522 else if ( key.exactMatch(text) )
524 Token keyToken = { Token::KeyKeyword , QString() };
525 Token sequenceToken = { Token::KeySequence , key.capturedTexts()[1].remove(' ') };
527 list << keyToken << sequenceToken;
529 if ( key.capturedTexts()[3].isEmpty() )
531 // capturedTexts()[2] is a command
532 Token commandToken = { Token::Command , key.capturedTexts()[2] };
533 list << commandToken;
535 else
537 // capturedTexts()[3] is the output string
538 Token outputToken = { Token::OutputText , key.capturedTexts()[3] };
539 list << outputToken;
542 else
544 kWarning() << "Line in keyboard translator file could not be understood:" << text;
547 return list;
550 QList<QString> KeyboardTranslatorManager::allTranslators()
552 if ( !_haveLoadedAll )
554 findTranslators();
557 return _translators.keys();
560 KeyboardTranslator::Entry::Entry()
561 : _keyCode(0)
562 , _modifiers(Qt::NoModifier)
563 , _modifierMask(Qt::NoModifier)
564 , _state(NoState)
565 , _stateMask(NoState)
566 , _command(NoCommand)
570 bool KeyboardTranslator::Entry::operator==(const Entry& rhs) const
572 return _keyCode == rhs._keyCode &&
573 _modifiers == rhs._modifiers &&
574 _modifierMask == rhs._modifierMask &&
575 _state == rhs._state &&
576 _stateMask == rhs._stateMask &&
577 _command == rhs._command &&
578 _text == rhs._text;
581 bool KeyboardTranslator::Entry::matches(int keyCode ,
582 Qt::KeyboardModifiers modifiers,
583 States state) const
585 if ( _keyCode != keyCode )
586 return false;
588 if ( (modifiers & _modifierMask) != (_modifiers & _modifierMask) )
589 return false;
591 // if modifiers is non-zero, the 'any modifier' state is implicit
592 if ( modifiers != 0 )
593 state |= AnyModifierState;
595 if ( (state & _stateMask) != (_state & _stateMask) )
596 return false;
598 // special handling for the 'Any Modifier' state, which checks for the presence of
599 // any or no modifiers. In this context, the 'keypad' modifier does not count.
600 bool anyModifiersSet = modifiers != 0 && modifiers != Qt::KeypadModifier;
601 if ( _stateMask & KeyboardTranslator::AnyModifierState )
603 // test fails if any modifier is required but none are set
604 if ( (_state & KeyboardTranslator::AnyModifierState) && !anyModifiersSet )
605 return false;
607 // test fails if no modifier is allowed but one or more are set
608 if ( !(_state & KeyboardTranslator::AnyModifierState) && anyModifiersSet )
609 return false;
612 return true;
614 QByteArray KeyboardTranslator::Entry::escapedText(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
616 QByteArray result(text(expandWildCards,modifiers));
618 for ( int i = 0 ; i < result.count() ; i++ )
620 char ch = result[i];
621 char replacement = 0;
623 switch ( ch )
625 case 27 : replacement = 'E'; break;
626 case 8 : replacement = 'b'; break;
627 case 12 : replacement = 'f'; break;
628 case 9 : replacement = 't'; break;
629 case 13 : replacement = 'r'; break;
630 case 10 : replacement = 'n'; break;
631 default:
632 // any character which is not printable is replaced by an equivalent
633 // \xhh escape sequence (where 'hh' are the corresponding hex digits)
634 if ( !QChar(ch).isPrint() )
635 replacement = 'x';
638 if ( replacement == 'x' )
640 result.replace(i,1,"\\x"+QByteArray(1,ch).toHex());
641 } else if ( replacement != 0 )
643 result.remove(i,1);
644 result.insert(i,'\\');
645 result.insert(i+1,replacement);
649 return result;
651 QByteArray KeyboardTranslator::Entry::unescape(const QByteArray& input) const
653 QByteArray result(input);
655 for ( int i = 0 ; i < result.count()-1 ; i++ )
658 QByteRef ch = result[i];
659 if ( ch == '\\' )
661 char replacement[2] = {0,0};
662 int charsToRemove = 2;
663 bool escapedChar = true;
665 switch ( result[i+1] )
667 case 'E' : replacement[0] = 27; break;
668 case 'b' : replacement[0] = 8 ; break;
669 case 'f' : replacement[0] = 12; break;
670 case 't' : replacement[0] = 9 ; break;
671 case 'r' : replacement[0] = 13; break;
672 case 'n' : replacement[0] = 10; break;
673 case 'x' :
675 // format is \xh or \xhh where 'h' is a hexadecimal
676 // digit from 0-9 or A-F which should be replaced
677 // with the corresponding character value
678 char hexDigits[3] = {0};
680 if ( (i < result.count()-2) && isxdigit(result[i+2]) )
681 hexDigits[0] = result[i+2];
682 if ( (i < result.count()-3) && isxdigit(result[i+3]) )
683 hexDigits[1] = result[i+3];
685 int charValue = 0;
686 sscanf(hexDigits,"%x",&charValue);
688 replacement[0] = (char)charValue;
690 charsToRemove = 2 + strlen(hexDigits);
692 break;
693 default:
694 escapedChar = false;
697 if ( escapedChar )
698 result.replace(i,charsToRemove,replacement);
702 return result;
705 void KeyboardTranslator::Entry::insertModifier( QString& item , int modifier ) const
707 if ( !(modifier & _modifierMask) )
708 return;
710 if ( modifier & _modifiers )
711 item += '+';
712 else
713 item += '-';
715 if ( modifier == Qt::ShiftModifier )
716 item += "Shift";
717 else if ( modifier == Qt::ControlModifier )
718 item += "Ctrl";
719 else if ( modifier == Qt::AltModifier )
720 item += "Alt";
721 else if ( modifier == Qt::MetaModifier )
722 item += "Meta";
723 else if ( modifier == Qt::KeypadModifier )
724 item += "KeyPad";
726 void KeyboardTranslator::Entry::insertState( QString& item , int state ) const
728 if ( !(state & _stateMask) )
729 return;
731 if ( state & _state )
732 item += '+' ;
733 else
734 item += '-' ;
736 if ( state == KeyboardTranslator::AlternateScreenState )
737 item += "AppScreen";
738 else if ( state == KeyboardTranslator::NewLineState )
739 item += "NewLine";
740 else if ( state == KeyboardTranslator::AnsiState )
741 item += "Ansi";
742 else if ( state == KeyboardTranslator::CursorKeysState )
743 item += "AppCuKeys";
744 else if ( state == KeyboardTranslator::AnyModifierState )
745 item += "AnyMod";
747 QString KeyboardTranslator::Entry::resultToString(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
749 if ( !_text.isEmpty() )
750 return escapedText(expandWildCards,modifiers);
751 else if ( _command == EraseCommand )
752 return "Erase";
753 else if ( _command == ScrollPageUpCommand )
754 return "ScrollPageUp";
755 else if ( _command == ScrollPageDownCommand )
756 return "ScrollPageDown";
757 else if ( _command == ScrollLineUpCommand )
758 return "ScrollLineUp";
759 else if ( _command == ScrollLineDownCommand )
760 return "ScrollLineDown";
761 else if ( _command == ScrollLockCommand )
762 return "ScrollLock";
764 return QString();
766 QString KeyboardTranslator::Entry::conditionToString() const
768 QString result = QKeySequence(_keyCode).toString();
770 // add modifiers
771 insertModifier( result , Qt::ShiftModifier );
772 insertModifier( result , Qt::ControlModifier );
773 insertModifier( result , Qt::AltModifier );
774 insertModifier( result , Qt::MetaModifier );
776 // add states
777 insertState( result , KeyboardTranslator::AlternateScreenState );
778 insertState( result , KeyboardTranslator::NewLineState );
779 insertState( result , KeyboardTranslator::AnsiState );
780 insertState( result , KeyboardTranslator::CursorKeysState );
781 insertState( result , KeyboardTranslator::AnyModifierState );
783 return result;
786 KeyboardTranslator::KeyboardTranslator(const QString& name)
787 : _name(name)
791 void KeyboardTranslator::setDescription(const QString& description)
793 _description = description;
795 QString KeyboardTranslator::description() const
797 return _description;
799 void KeyboardTranslator::setName(const QString& name)
801 _name = name;
803 QString KeyboardTranslator::name() const
805 return _name;
808 QList<KeyboardTranslator::Entry> KeyboardTranslator::entries() const
810 return _entries.values();
813 void KeyboardTranslator::addEntry(const Entry& entry)
815 const int keyCode = entry.keyCode();
816 _entries.insert(keyCode,entry);
818 void KeyboardTranslator::replaceEntry(const Entry& existing , const Entry& replacement)
820 if ( !existing.isNull() )
821 _entries.remove(existing.keyCode(),existing);
822 _entries.insert(replacement.keyCode(),replacement);
824 void KeyboardTranslator::removeEntry(const Entry& entry)
826 _entries.remove(entry.keyCode(),entry);
828 KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const
830 if ( _entries.contains(keyCode) )
832 QList<Entry> entriesForKey = _entries.values(keyCode);
834 QListIterator<Entry> iter(entriesForKey);
836 while (iter.hasNext())
838 const Entry& next = iter.next();
839 if ( next.matches(keyCode,modifiers,state) )
840 return next;
843 return Entry(); // entry not found
845 else
847 return Entry();
850 void KeyboardTranslatorManager::addTranslator(KeyboardTranslator* translator)
852 _translators.insert(translator->name(),translator);
854 if ( !saveTranslator(translator) )
855 kWarning() << "Unable to save translator" << translator->name()
856 << "to disk.";
858 bool KeyboardTranslatorManager::deleteTranslator(const QString& name)
860 Q_ASSERT( _translators.contains(name) );
862 // locate and delete
863 QString path = findTranslatorPath(name);
864 if ( QFile::remove(path) )
866 _translators.remove(name);
867 return true;
869 else
871 kWarning() << "Failed to remove translator - " << path;
872 return false;
875 K_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager )
876 KeyboardTranslatorManager* KeyboardTranslatorManager::instance()
878 return theKeyboardTranslatorManager;