File indexing completed on 2024-04-28 05:50:42
0001 /* 0002 This source file is part of Konsole, a terminal emulator. 0003 0004 SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #ifndef KEYBOARDTRANSLATOR_H 0010 #define KEYBOARDTRANSLATOR_H 0011 0012 // Qt 0013 #include <QList> 0014 #include <QLoggingCategory> 0015 #include <QMetaType> 0016 #include <QMultiHash> 0017 #include <QString> 0018 0019 class QIODevice; 0020 class QTextStream; 0021 0022 Q_DECLARE_LOGGING_CATEGORY(KonsoleKeyTrDebug) 0023 0024 namespace Konsole 0025 { 0026 /** 0027 * A converter which maps between key sequences pressed by the user and the 0028 * character strings which should be sent to the terminal and commands 0029 * which should be invoked when those character sequences are pressed. 0030 * 0031 * Konsole supports multiple keyboard translators, allowing the user to 0032 * specify the character sequences which are sent to the terminal 0033 * when particular key sequences are pressed. 0034 * 0035 * A key sequence is defined as a key code, associated keyboard modifiers 0036 * (Shift,Ctrl,Alt,Meta etc.) and state flags which indicate the state 0037 * which the terminal must be in for the key sequence to apply. 0038 */ 0039 class KeyboardTranslator 0040 { 0041 public: 0042 /** 0043 * The meaning of a particular key sequence may depend upon the state which 0044 * the terminal emulation is in. Therefore findEntry() may return a different 0045 * Entry depending upon the state flags supplied. 0046 * 0047 * This enum describes the states which may be associated with a particular 0048 * entry in the keyboard translation entry. 0049 */ 0050 enum State { 0051 /** Indicates that no special state is active */ 0052 NoState = 0, 0053 /** 0054 * TODO More documentation 0055 */ 0056 NewLineState = 1, 0057 /** 0058 * Indicates that the terminal is in 'ANSI' mode. 0059 * TODO: More documentation 0060 */ 0061 AnsiState = 2, 0062 /** 0063 * TODO More documentation 0064 */ 0065 CursorKeysState = 4, 0066 /** 0067 * Indicates that the alternate screen ( typically used by interactive programs 0068 * such as screen or vim ) is active 0069 */ 0070 AlternateScreenState = 8, 0071 /** Indicates that any of the modifier keys is active. */ 0072 AnyModifierState = 16, 0073 /** Indicates that the numpad is in application mode. */ 0074 ApplicationKeypadState = 32, 0075 }; 0076 Q_DECLARE_FLAGS(States, State) 0077 0078 /** 0079 * This enum describes commands which are associated with particular key sequences. 0080 */ 0081 enum Command { 0082 /** Indicates that no command is associated with this command sequence */ 0083 NoCommand = 0, 0084 /** TODO Document me */ 0085 SendCommand = 1, 0086 /** Scroll the terminal display up one page */ 0087 ScrollPageUpCommand = 2, 0088 /** Scroll the terminal display down one page */ 0089 ScrollPageDownCommand = 4, 0090 /** Scroll the terminal display up one line */ 0091 ScrollLineUpCommand = 8, 0092 /** Scroll the terminal display down one line */ 0093 ScrollLineDownCommand = 16, 0094 /** Scroll the terminal display up to the start of history */ 0095 ScrollUpToTopCommand = 32, 0096 /** Scroll the terminal display down to the end of history */ 0097 ScrollDownToBottomCommand = 64, 0098 /** Scroll the terminal display up to the next prompt */ 0099 ScrollPromptUpCommand = 128, 0100 /** Scroll the terminal display down to the next prompt */ 0101 ScrollPromptDownCommand = 256, 0102 /** Echos the operating system specific erase character. */ 0103 EraseCommand = 512, 0104 }; 0105 Q_DECLARE_FLAGS(Commands, Command) 0106 0107 /** 0108 * Represents an association between a key sequence pressed by the user 0109 * and the character sequence and commands associated with it for a particular 0110 * KeyboardTranslator. 0111 */ 0112 class Entry 0113 { 0114 public: 0115 /** 0116 * Constructs a new entry for a keyboard translator. 0117 */ 0118 Entry(); 0119 0120 /** 0121 * Returns true if this entry is null. 0122 * This is true for newly constructed entries which have no properties set. 0123 */ 0124 bool isNull() const; 0125 0126 /** Returns the commands associated with this entry */ 0127 Command command() const; 0128 /** Sets the command associated with this entry. */ 0129 void setCommand(Command aCommand); 0130 0131 /** 0132 * Returns the character sequence associated with this entry, optionally replacing 0133 * wildcard '*' characters with numbers to indicate the keyboard modifiers being pressed. 0134 * 0135 * TODO: The numbers used to replace '*' characters are taken from the Konsole/KDE 3 code. 0136 * Document them. 0137 * 0138 * @param expandWildCards Specifies whether wild cards (occurrences of the '*' character) in 0139 * the entry should be replaced with a number to indicate the modifier keys being pressed. 0140 * 0141 * @param keyboardModifiers The keyboard modifiers being pressed. 0142 */ 0143 QByteArray text(bool expandWildCards = false, Qt::KeyboardModifiers keyboardModifiers = Qt::NoModifier) const; 0144 0145 /** Sets the character sequence associated with this entry */ 0146 void setText(const QByteArray &aText); 0147 0148 /** 0149 * Returns the character sequence associated with this entry, 0150 * with any non-printable characters replaced with escape sequences. 0151 * 0152 * eg. \\E for Escape, \\t for tab, \\n for new line. 0153 * 0154 * @param expandWildCards See text() 0155 * @param keyboardModifiers The keyboard modifiers being pressed. 0156 */ 0157 QByteArray escapedText(bool expandWildCards = false, Qt::KeyboardModifiers keyboardModifiers = Qt::NoModifier) const; 0158 0159 /** Returns the character code ( from the Qt::Key enum ) associated with this entry */ 0160 int keyCode() const; 0161 /** Sets the character code associated with this entry */ 0162 void setKeyCode(int aKeyCode); 0163 0164 /** 0165 * Returns a bitwise-OR of the enabled keyboard modifiers associated with this entry. 0166 * If a modifier is set in modifierMask() but not in modifiers(), this means that the entry 0167 * only matches when that modifier is NOT pressed. 0168 * 0169 * If a modifier is not set in modifierMask() then the entry matches whether the modifier 0170 * is pressed or not. 0171 */ 0172 Qt::KeyboardModifiers modifiers() const; 0173 0174 /** Returns the keyboard modifiers which are valid in this entry. See modifiers() */ 0175 Qt::KeyboardModifiers modifierMask() const; 0176 0177 /** See modifiers() */ 0178 void setModifiers(Qt::KeyboardModifiers modifiers); 0179 /** See modifierMask() and modifiers() */ 0180 void setModifierMask(Qt::KeyboardModifiers mask); 0181 0182 /** 0183 * Returns a bitwise-OR of the enabled state flags associated with this entry. 0184 * If flag is set in stateMask() but not in state(), this means that the entry only 0185 * matches when the terminal is NOT in that state. 0186 * 0187 * If a state is not set in stateMask() then the entry matches whether the terminal 0188 * is in that state or not. 0189 */ 0190 States state() const; 0191 0192 /** Returns the state flags which are valid in this entry. See state() */ 0193 States stateMask() const; 0194 0195 /** See state() */ 0196 void setState(States aState); 0197 /** See stateMask() */ 0198 void setStateMask(States aStateMask); 0199 0200 /** 0201 * Returns this entry's conditions ( ie. its key code, modifier and state criteria ) 0202 * as a string. 0203 */ 0204 QString conditionToString() const; 0205 0206 /** 0207 * Returns this entry's result ( ie. its command or character sequence ) 0208 * as a string. 0209 * 0210 * @param expandWildCards See text() 0211 * @param keyboardModifiers The keyboard modifiers being pressed. 0212 */ 0213 QString resultToString(bool expandWildCards = false, Qt::KeyboardModifiers keyboardModifiers = Qt::NoModifier) const; 0214 0215 /** 0216 * Returns true if this entry matches the given key sequence, specified 0217 * as a combination of @p testKeyCode , @p testKeyboardModifiers and @p testState. 0218 */ 0219 bool matches(int testKeyCode, Qt::KeyboardModifiers testKeyboardModifiers, States testState) const; 0220 0221 bool operator==(const Entry &rhs) const; 0222 0223 private: 0224 void insertModifier(QString &item, int modifier) const; 0225 void insertState(QString &item, int state) const; 0226 QByteArray unescape(const QByteArray &text) const; 0227 0228 int _keyCode; 0229 Qt::KeyboardModifiers _modifiers; 0230 Qt::KeyboardModifiers _modifierMask; 0231 States _state; 0232 States _stateMask; 0233 0234 Command _command; 0235 QByteArray _text; 0236 }; 0237 0238 /** Constructs a new keyboard translator with the given @p name */ 0239 explicit KeyboardTranslator(const QString &name); 0240 0241 /** Returns the name of this keyboard translator */ 0242 QString name() const; 0243 0244 /** Sets the name of this keyboard translator */ 0245 void setName(const QString &name); 0246 0247 /** Returns the descriptive name of this keyboard translator */ 0248 QString description() const; 0249 0250 /** Sets the descriptive name of this keyboard translator */ 0251 void setDescription(const QString &description); 0252 0253 /** 0254 * Looks for an entry in this keyboard translator which matches the given 0255 * key code, keyboard modifiers and state flags. 0256 * 0257 * Returns the matching entry if found or a null Entry otherwise ( ie. 0258 * entry.isNull() will return true ) 0259 * 0260 * @param keyCode A key code from the Qt::Key enum 0261 * @param modifiers A combination of modifiers 0262 * @param state Optional flags which specify the current state of the terminal 0263 */ 0264 Entry findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state = NoState) const; 0265 0266 /** 0267 * Adds an entry to this keyboard translator's table. Entries can be looked up according 0268 * to their key sequence using findEntry() 0269 */ 0270 void addEntry(const Entry &entry); 0271 0272 /** 0273 * Replaces an entry in the translator. If the @p existing entry is null, 0274 * then this is equivalent to calling addEntry(@p replacement) 0275 */ 0276 void replaceEntry(const Entry &existing, const Entry &replacement); 0277 0278 /** 0279 * Removes an entry from the table. 0280 */ 0281 void removeEntry(const Entry &entry); 0282 0283 /** Returns a list of all entries in the translator. */ 0284 QList<Entry> entries() const; 0285 0286 private: 0287 // All entries in this translator, indexed by their keycode 0288 QMultiHash<int, Entry> _entries; 0289 0290 QString _name; 0291 QString _description; 0292 }; 0293 Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::States) 0294 Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands) 0295 0296 inline int KeyboardTranslator::Entry::keyCode() const 0297 { 0298 return _keyCode; 0299 } 0300 0301 inline void KeyboardTranslator::Entry::setKeyCode(int aKeyCode) 0302 { 0303 _keyCode = aKeyCode; 0304 } 0305 0306 inline void KeyboardTranslator::Entry::setModifiers(Qt::KeyboardModifiers modifiers) 0307 { 0308 _modifiers = modifiers; 0309 } 0310 0311 inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifiers() const 0312 { 0313 return _modifiers; 0314 } 0315 0316 inline void KeyboardTranslator::Entry::setModifierMask(Qt::KeyboardModifiers mask) 0317 { 0318 _modifierMask = mask; 0319 } 0320 0321 inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifierMask() const 0322 { 0323 return _modifierMask; 0324 } 0325 0326 inline bool KeyboardTranslator::Entry::isNull() const 0327 { 0328 return *this == Entry(); 0329 } 0330 0331 inline void KeyboardTranslator::Entry::setCommand(Command aCommand) 0332 { 0333 _command = aCommand; 0334 } 0335 0336 inline KeyboardTranslator::Command KeyboardTranslator::Entry::command() const 0337 { 0338 return _command; 0339 } 0340 0341 inline void KeyboardTranslator::Entry::setText(const QByteArray &aText) 0342 { 0343 _text = unescape(aText); 0344 } 0345 0346 inline int oneOrZero(int value) 0347 { 0348 return value ? 1 : 0; 0349 } 0350 0351 inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards, Qt::KeyboardModifiers keyboardModifiers) const 0352 { 0353 QByteArray expandedText = _text; 0354 0355 if (expandWildCards) { 0356 int modifierValue = 1; 0357 modifierValue += oneOrZero(keyboardModifiers & Qt::ShiftModifier); 0358 modifierValue += oneOrZero(keyboardModifiers & Qt::AltModifier) << 1; 0359 modifierValue += oneOrZero(keyboardModifiers & Qt::ControlModifier) << 2; 0360 0361 for (int i = 0; i < _text.length(); i++) { 0362 if (expandedText[i] == '*') { 0363 expandedText[i] = '0' + modifierValue; 0364 } 0365 } 0366 } 0367 0368 return expandedText; 0369 } 0370 0371 inline void KeyboardTranslator::Entry::setState(States aState) 0372 { 0373 _state = aState; 0374 } 0375 0376 inline KeyboardTranslator::States KeyboardTranslator::Entry::state() const 0377 { 0378 return _state; 0379 } 0380 0381 inline void KeyboardTranslator::Entry::setStateMask(States aStateMask) 0382 { 0383 _stateMask = aStateMask; 0384 } 0385 0386 inline KeyboardTranslator::States KeyboardTranslator::Entry::stateMask() const 0387 { 0388 return _stateMask; 0389 } 0390 } 0391 0392 Q_DECLARE_METATYPE(Konsole::KeyboardTranslator::Entry) 0393 Q_DECLARE_METATYPE(const Konsole::KeyboardTranslator *) 0394 0395 #endif // KEYBOARDTRANSLATOR_H