source: ogBrowser-Git/qtermwidget/lib/KeyboardTranslator.h @ c0cec9d

jenkinsmain
Last change on this file since c0cec9d was 64efc22, checked in by Vadim Troshchinskiy <vtroshchinskiy@…>, 19 months ago

Update qtermwidget to modern version

  • Property mode set to 100644
File size: 19.6 KB
Line 
1/*
2    This source file is part of Konsole, a terminal emulator.
3
4    Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
5
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.
10
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.
15
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.
20*/
21
22#ifndef KEYBOARDTRANSLATOR_H
23#define KEYBOARDTRANSLATOR_H
24
25// Qt
26#include <QHash>
27#include <QList>
28#include <QKeySequence>
29#include <QMetaType>
30#include <QVarLengthArray>
31
32// Konsole
33//#include "konsole_export.h"
34#define KONSOLEPRIVATE_EXPORT
35
36class QIODevice;
37class QTextStream;
38
39namespace Konsole
40{
41
42/**
43 * A convertor which maps between key sequences pressed by the user and the
44 * character strings which should be sent to the terminal and commands
45 * which should be invoked when those character sequences are pressed.
46 *
47 * Konsole supports multiple keyboard translators, allowing the user to
48 * specify the character sequences which are sent to the terminal
49 * when particular key sequences are pressed.
50 *
51 * A key sequence is defined as a key code, associated keyboard modifiers
52 * (Shift,Ctrl,Alt,Meta etc.) and state flags which indicate the state
53 * which the terminal must be in for the key sequence to apply.
54 */
55class KeyboardTranslator
56{
57public:
58    /**
59     * The meaning of a particular key sequence may depend upon the state which
60     * the terminal emulation is in.  Therefore findEntry() may return a different
61     * Entry depending upon the state flags supplied.
62     *
63     * This enum describes the states which may be associated with with a particular
64     * entry in the keyboard translation entry.
65     */
66    enum State
67    {
68        /** Indicates that no special state is active */
69        NoState = 0,
70        /**
71         * TODO More documentation
72         */
73        NewLineState = 1,
74        /**
75         * Indicates that the terminal is in 'Ansi' mode.
76         * TODO: More documentation
77         */
78        AnsiState = 2,
79        /**
80         * TODO More documentation
81         */
82        CursorKeysState = 4,
83        /**
84         * Indicates that the alternate screen ( typically used by interactive programs
85         * such as screen or vim ) is active
86         */
87        AlternateScreenState = 8,
88        /** Indicates that any of the modifier keys is active. */
89        AnyModifierState = 16,
90        /** Indicates that the numpad is in application mode. */
91        ApplicationKeypadState = 32
92    };
93    Q_DECLARE_FLAGS(States,State)
94
95    /**
96     * This enum describes commands which are associated with particular key sequences.
97     */
98    enum Command
99    {
100        /** Indicates that no command is associated with this command sequence */
101        NoCommand = 0,
102        /** TODO Document me */
103        SendCommand = 1,
104        /** Scroll the terminal display up one page */
105        ScrollPageUpCommand = 2,
106        /** Scroll the terminal display down one page */
107        ScrollPageDownCommand = 4,
108        /** Scroll the terminal display up one line */
109        ScrollLineUpCommand = 8,
110        /** Scroll the terminal display down one line */
111        ScrollLineDownCommand = 16,
112        /** Toggles scroll lock mode */
113        ScrollLockCommand = 32,
114        /** Scroll the terminal display up to the start of history */
115        ScrollUpToTopCommand = 64,
116        /** Scroll the terminal display down to the end of history */
117        ScrollDownToBottomCommand = 128,
118        /** Echos the operating system specific erase character. */
119        EraseCommand = 256
120    };
121    Q_DECLARE_FLAGS(Commands,Command)
122
123    /**
124     * Represents an association between a key sequence pressed by the user
125     * and the character sequence and commands associated with it for a particular
126     * KeyboardTranslator.
127     */
128    class Entry
129    {
130    public:
131        /**
132         * Constructs a new entry for a keyboard translator.
133         */
134        Entry();
135
136        /**
137         * Returns true if this entry is null.
138         * This is true for newly constructed entries which have no properties set.
139         */
140        bool isNull() const;
141
142        /** Returns the commands associated with this entry */
143        Command command() const;
144        /** Sets the command associated with this entry. */
145        void setCommand(Command command);
146
147        /**
148         * Returns the character sequence associated with this entry, optionally replacing
149         * wildcard '*' characters with numbers to indicate the keyboard modifiers being pressed.
150         *
151         * TODO: The numbers used to replace '*' characters are taken from the Konsole/KDE 3 code.
152         * Document them.
153         *
154         * @param expandWildCards Specifies whether wild cards (occurrences of the '*' character) in
155         * the entry should be replaced with a number to indicate the modifier keys being pressed.
156         *
157         * @param modifiers The keyboard modifiers being pressed.
158         */
159        QByteArray text(bool expandWildCards = false,
160                        Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
161
162        /** Sets the character sequence associated with this entry */
163        void setText(const QByteArray& text);
164
165        /**
166         * Returns the character sequence associated with this entry,
167         * with any non-printable characters replaced with escape sequences.
168         *
169         * eg. \\E for Escape, \\t for tab, \\n for new line.
170         *
171         * @param expandWildCards See text()
172         * @param modifiers See text()
173         */
174        QByteArray escapedText(bool expandWildCards = false,
175                               Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
176
177        /** Returns the character code ( from the Qt::Key enum ) associated with this entry */
178        int keyCode() const;
179        /** Sets the character code associated with this entry */
180        void setKeyCode(int keyCode);
181
182        /**
183         * Returns a bitwise-OR of the enabled keyboard modifiers associated with this entry.
184         * If a modifier is set in modifierMask() but not in modifiers(), this means that the entry
185         * only matches when that modifier is NOT pressed.
186         *
187         * If a modifier is not set in modifierMask() then the entry matches whether the modifier
188         * is pressed or not.
189         */
190        Qt::KeyboardModifiers modifiers() const;
191
192        /** Returns the keyboard modifiers which are valid in this entry.  See modifiers() */
193        Qt::KeyboardModifiers modifierMask() const;
194
195        /** See modifiers() */
196        void setModifiers( Qt::KeyboardModifiers modifiers );
197        /** See modifierMask() and modifiers() */
198        void setModifierMask( Qt::KeyboardModifiers modifiers );
199
200        /**
201         * Returns a bitwise-OR of the enabled state flags associated with this entry.
202         * If flag is set in stateMask() but not in state(), this means that the entry only
203         * matches when the terminal is NOT in that state.
204         *
205         * If a state is not set in stateMask() then the entry matches whether the terminal
206         * is in that state or not.
207         */
208        States state() const;
209
210        /** Returns the state flags which are valid in this entry.  See state() */
211        States stateMask() const;
212
213        /** See state() */
214        void setState( States state );
215        /** See stateMask() */
216        void setStateMask( States mask );
217
218        /**
219         * Returns the key code and modifiers associated with this entry
220         * as a QKeySequence
221         */
222        //QKeySequence keySequence() const;
223
224        /**
225         * Returns this entry's conditions ( ie. its key code, modifier and state criteria )
226         * as a string.
227         */
228        QString conditionToString() const;
229
230        /**
231         * Returns this entry's result ( ie. its command or character sequence )
232         * as a string.
233         *
234         * @param expandWildCards See text()
235         * @param modifiers See text()
236         */
237        QString resultToString(bool expandWildCards = false,
238                               Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
239
240        /**
241         * Returns true if this entry matches the given key sequence, specified
242         * as a combination of @p keyCode , @p modifiers and @p state.
243         */
244        bool matches( int keyCode ,
245                      Qt::KeyboardModifiers modifiers ,
246                      States flags ) const;
247
248        bool operator==(const Entry& rhs) const;
249
250    private:
251        void insertModifier( QString& item , int modifier ) const;
252        void insertState( QString& item , int state ) const;
253        QByteArray unescape(const QByteArray& text) const;
254
255        int _keyCode;
256        Qt::KeyboardModifiers _modifiers;
257        Qt::KeyboardModifiers _modifierMask;
258        States _state;
259        States _stateMask;
260
261        Command _command;
262        QByteArray _text;
263    };
264
265    /** Constructs a new keyboard translator with the given @p name */
266    KeyboardTranslator(const QString& name);
267
268    //KeyboardTranslator(const KeyboardTranslator& other);
269
270    /** Returns the name of this keyboard translator */
271    QString name() const;
272
273    /** Sets the name of this keyboard translator */
274    void setName(const QString& name);
275
276    /** Returns the descriptive name of this keyboard translator */
277    QString description() const;
278
279    /** Sets the descriptive name of this keyboard translator */
280    void setDescription(const QString& description);
281
282    /**
283     * Looks for an entry in this keyboard translator which matches the given
284     * key code, keyboard modifiers and state flags.
285     *
286     * Returns the matching entry if found or a null Entry otherwise ( ie.
287     * entry.isNull() will return true )
288     *
289     * @param keyCode A key code from the Qt::Key enum
290     * @param modifiers A combination of modifiers
291     * @param state Optional flags which specify the current state of the terminal
292     */
293    Entry findEntry(int keyCode ,
294                    Qt::KeyboardModifiers modifiers ,
295                    States state = NoState) const;
296
297    /**
298     * Adds an entry to this keyboard translator's table.  Entries can be looked up according
299     * to their key sequence using findEntry()
300     */
301    void addEntry(const Entry& entry);
302
303    /**
304     * Replaces an entry in the translator.  If the @p existing entry is null,
305     * then this is equivalent to calling addEntry(@p replacement)
306     */
307    void replaceEntry(const Entry& existing , const Entry& replacement);
308
309    /**
310     * Removes an entry from the table.
311     */
312    void removeEntry(const Entry& entry);
313
314    /** Returns a list of all entries in the translator. */
315    QList<Entry> entries() const;
316
317    /** The modifier code for the actual Ctrl key on this OS. */
318    static const Qt::KeyboardModifier CTRL_MOD;
319
320private:
321
322    QMultiHash<int,Entry> _entries; // entries in this keyboard translation,
323                                                 // entries are indexed according to
324                                                 // their keycode
325    QString _name;
326    QString _description;
327};
328Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::States)
329Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands)
330
331/**
332 * Parses the contents of a Keyboard Translator (.keytab) file and
333 * returns the entries found in it.
334 *
335 * Usage example:
336 *
337 * @code
338 *  QFile source( "/path/to/keytab" );
339 *  source.open( QIODevice::ReadOnly );
340 *
341 *  KeyboardTranslator* translator = new KeyboardTranslator( "name-of-translator" );
342 *
343 *  KeyboardTranslatorReader reader(source);
344 *  while ( reader.hasNextEntry() )
345 *      translator->addEntry(reader.nextEntry());
346 *
347 *  source.close();
348 *
349 *  if ( !reader.parseError() )
350 *  {
351 *      // parsing succeeded, do something with the translator
352 *  }
353 *  else
354 *  {
355 *      // parsing failed
356 *  }
357 * @endcode
358 */
359class KeyboardTranslatorReader
360{
361public:
362    /** Constructs a new reader which parses the given @p source */
363    KeyboardTranslatorReader( QIODevice* source );
364
365    /**
366     * Returns the description text.
367     * TODO: More documentation
368     */
369    QString description() const;
370
371    /** Returns true if there is another entry in the source stream */
372    bool hasNextEntry() const;
373    /** Returns the next entry found in the source stream */
374    KeyboardTranslator::Entry nextEntry();
375
376    /**
377     * Returns true if an error occurred whilst parsing the input or
378     * false if no error occurred.
379     */
380    bool parseError();
381
382    /**
383     * Parses a condition and result string for a translator entry
384     * and produces a keyboard translator entry.
385     *
386     * The condition and result strings are in the same format as in
387     */
388    static KeyboardTranslator::Entry createEntry( const QString& condition ,
389                                                  const QString& result );
390private:
391    struct Token
392    {
393        enum Type
394        {
395            TitleKeyword,
396            TitleText,
397            KeyKeyword,
398            KeySequence,
399            Command,
400            OutputText
401        };
402        Type type;
403        QString text;
404    };
405    QList<Token> tokenize(const QString&);
406    void readNext();
407    bool decodeSequence(const QString& ,
408                                int& keyCode,
409                                Qt::KeyboardModifiers& modifiers,
410                                Qt::KeyboardModifiers& modifierMask,
411                                KeyboardTranslator::States& state,
412                                KeyboardTranslator::States& stateFlags);
413
414    static bool parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier);
415    static bool parseAsStateFlag(const QString& item , KeyboardTranslator::State& state);
416    static bool parseAsKeyCode(const QString& item , int& keyCode);
417       static bool parseAsCommand(const QString& text , KeyboardTranslator::Command& command);
418
419    QIODevice* _source;
420    QString _description;
421    KeyboardTranslator::Entry _nextEntry;
422    bool _hasNext;
423};
424
425/** Writes a keyboard translation to disk. */
426class KeyboardTranslatorWriter
427{
428public:
429    /**
430     * Constructs a new writer which saves data into @p destination.
431     * The caller is responsible for closing the device when writing is complete.
432     */
433    KeyboardTranslatorWriter(QIODevice* destination);
434    ~KeyboardTranslatorWriter();
435
436    /**
437     * Writes the header for the keyboard translator.
438     * @param description Description of the keyboard translator.
439     */
440    void writeHeader( const QString& description );
441    /** Writes a translator entry. */
442    void writeEntry( const KeyboardTranslator::Entry& entry );
443
444private:
445    QIODevice* _destination;
446    QTextStream* _writer;
447};
448
449/**
450 * Manages the keyboard translations available for use by terminal sessions,
451 * see KeyboardTranslator.
452 */
453class KONSOLEPRIVATE_EXPORT KeyboardTranslatorManager
454{
455public:
456    /**
457     * Constructs a new KeyboardTranslatorManager and loads the list of
458     * available keyboard translations.
459     *
460     * The keyboard translations themselves are not loaded until they are
461     * first requested via a call to findTranslator()
462     */
463    KeyboardTranslatorManager();
464    ~KeyboardTranslatorManager();
465
466    KeyboardTranslatorManager(const KeyboardTranslatorManager&) = delete;
467    KeyboardTranslatorManager& operator=(const KeyboardTranslatorManager&) = delete;
468
469    /**
470     * Adds a new translator.  If a translator with the same name
471     * already exists, it will be replaced by the new translator.
472     *
473     * TODO: More documentation.
474     */
475    void addTranslator(KeyboardTranslator* translator);
476
477    /**
478     * Deletes a translator.  Returns true on successful deletion or false otherwise.
479     *
480     * TODO: More documentation
481     */
482    bool deleteTranslator(const QString& name);
483
484    /** Returns the default translator for Konsole. */
485    const KeyboardTranslator* defaultTranslator();
486
487    /**
488     * Returns the keyboard translator with the given name or 0 if no translator
489     * with that name exists.
490     *
491     * The first time that a translator with a particular name is requested,
492     * the on-disk .keyboard file is loaded and parsed.
493     */
494    const KeyboardTranslator* findTranslator(const QString& name);
495    /**
496     * Returns a list of the names of available keyboard translators.
497     *
498     * The first time this is called, a search for available
499     * translators is started.
500     */
501    QList<QString> allTranslators();
502
503    /** Returns the global KeyboardTranslatorManager instance. */
504   static KeyboardTranslatorManager* instance();
505
506private:
507    static const QByteArray defaultTranslatorText;
508
509    void findTranslators(); // locate the available translators
510    KeyboardTranslator* loadTranslator(const QString& name); // loads the translator
511                                                             // with the given name
512    KeyboardTranslator* loadTranslator(QIODevice* device,const QString& name);
513
514    bool saveTranslator(const KeyboardTranslator* translator);
515    QString findTranslatorPath(const QString& name);
516
517    QHash<QString,KeyboardTranslator*> _translators; // maps translator-name -> KeyboardTranslator
518                                                     // instance
519    bool _haveLoadedAll;
520};
521
522inline int KeyboardTranslator::Entry::keyCode() const { return _keyCode; }
523inline void KeyboardTranslator::Entry::setKeyCode(int keyCode) { _keyCode = keyCode; }
524
525inline void KeyboardTranslator::Entry::setModifiers( Qt::KeyboardModifiers modifier )
526{
527    _modifiers = modifier;
528}
529inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifiers() const { return _modifiers; }
530
531inline void  KeyboardTranslator::Entry::setModifierMask( Qt::KeyboardModifiers mask )
532{
533   _modifierMask = mask;
534}
535inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifierMask() const { return _modifierMask; }
536
537inline bool KeyboardTranslator::Entry::isNull() const
538{
539    return ( *this == Entry() );
540}
541
542inline void KeyboardTranslator::Entry::setCommand( Command command )
543{
544    _command = command;
545}
546inline KeyboardTranslator::Command KeyboardTranslator::Entry::command() const { return _command; }
547
548inline void KeyboardTranslator::Entry::setText( const QByteArray& text )
549{
550    _text = unescape(text);
551}
552inline int oneOrZero(int value)
553{
554    return value ? 1 : 0;
555}
556inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
557{
558    QByteArray expandedText = _text;
559
560    if (expandWildCards)
561    {
562        int modifierValue = 1;
563        modifierValue += oneOrZero(modifiers & Qt::ShiftModifier);
564        modifierValue += oneOrZero(modifiers & Qt::AltModifier) << 1;
565        modifierValue += oneOrZero(modifiers & KeyboardTranslator::CTRL_MOD) << 2;
566
567        for (int i=0;i<_text.length();i++)
568        {
569            if (expandedText[i] == '*')
570                expandedText[i] = '0' + modifierValue;
571        }
572    }
573
574    return expandedText;
575}
576
577inline void KeyboardTranslator::Entry::setState( States state )
578{
579    _state = state;
580}
581inline KeyboardTranslator::States KeyboardTranslator::Entry::state() const { return _state; }
582
583inline void KeyboardTranslator::Entry::setStateMask( States stateMask )
584{
585    _stateMask = stateMask;
586}
587inline KeyboardTranslator::States KeyboardTranslator::Entry::stateMask() const { return _stateMask; }
588
589}
590
591Q_DECLARE_METATYPE(Konsole::KeyboardTranslator::Entry)
592Q_DECLARE_METATYPE(const Konsole::KeyboardTranslator*)
593
594#endif // KEYBOARDTRANSLATOR_H
595
Note: See TracBrowser for help on using the repository browser.