GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
KeyboardTranslator.h
Go to the documentation of this file.
1 /*
2  This source file is part of Konsole, a terminal emulator.
3 
4  Copyright (C) 2007, 2013 by Robert Knight <robertknight@gmail.com>
5 
6  Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  02110-1301 USA.
22 */
23 
24 #ifndef KEYBOARDTRANSLATOR_H
25 #define KEYBOARDTRANSLATOR_H
26 
27 // Qt
28 #include <QtCore/QHash>
29 #include <QtCore/QList>
30 #include <QKeySequence>
31 #include <QtCore/QMetaType>
32 #include <QtCore/QVarLengthArray>
33 #include <QtCore>
34 
35 typedef void (*CleanUpFunction)();
36 
37 /**
38  * @internal
39  *
40  * Helper class for K_GLOBAL_STATIC to clean up the object on library unload or application
41  * shutdown.
42  */
44 {
45  public:
47 
48  inline ~CleanUpGlobalStatic() { func(); }
49 };
50 
51 
52 //these directives are taken from the heart of kdecore
53 
54 # define K_GLOBAL_STATIC_STRUCT_NAME(NAME)
55 
56 #if QT_VERSION < 0x040400
57 # define Q_BASIC_ATOMIC_INITIALIZER Q_ATOMIC_INIT
58 # define testAndSetOrdered testAndSet
59 #endif
60 
61 #define K_GLOBAL_STATIC(TYPE, NAME) K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
62 
63 #define K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
64 static QBasicAtomicPointer<TYPE > _k_static_##NAME = Q_BASIC_ATOMIC_INITIALIZER(0); \
65 static bool _k_static_##NAME##_destroyed; \
66 static struct K_GLOBAL_STATIC_STRUCT_NAME(NAME) \
67 { \
68  bool isDestroyed() \
69  { \
70  return _k_static_##NAME##_destroyed; \
71  } \
72  inline operator TYPE*() \
73  { \
74  return operator->(); \
75  } \
76  inline TYPE *operator->() \
77  { \
78  if (!_k_static_##NAME) { \
79  if (isDestroyed()) { \
80  qFatal("Fatal Error: Accessed global static '%s *%s()' after destruction. " \
81  "Defined at %s:%d", #TYPE, #NAME, __FILE__, __LINE__); \
82  } \
83  TYPE *x = new TYPE ARGS; \
84  if (!_k_static_##NAME.testAndSetOrdered(0, x) \
85  && _k_static_##NAME != x ) { \
86  delete x; \
87  } else { \
88  static CleanUpGlobalStatic cleanUpObject = { destroy }; \
89  } \
90  } \
91  return _k_static_##NAME; \
92  } \
93  inline TYPE &operator*() \
94  { \
95  return *operator->(); \
96  } \
97  static void destroy() \
98  { \
99  _k_static_##NAME##_destroyed = true; \
100  TYPE *x = _k_static_##NAME; \
101  _k_static_##NAME = 0; \
102  delete x; \
103  } \
104 } NAME;
105 
106 
107 
108 
109 
110 class QIODevice;
111 class QTextStream;
112 
113 /**
114  * A convertor which maps between key sequences pressed by the user and the
115  * character strings which should be sent to the terminal and commands
116  * which should be invoked when those character sequences are pressed.
117  *
118  * Konsole supports multiple keyboard translators, allowing the user to
119  * specify the character sequences which are sent to the terminal
120  * when particular key sequences are pressed.
121  *
122  * A key sequence is defined as a key code, associated keyboard modifiers
123  * (Shift,Ctrl,Alt,Meta etc.) and state flags which indicate the state
124  * which the terminal must be in for the key sequence to apply.
125  */
127 {
128 public:
129  /**
130  * The meaning of a particular key sequence may depend upon the state which
131  * the terminal emulation is in. Therefore findEntry() may return a different
132  * Entry depending upon the state flags supplied.
133  *
134  * This enum describes the states which may be associated with with a particular
135  * entry in the keyboard translation entry.
136  */
137  enum State
138  {
139  /** Indicates that no special state is active */
140  NoState = 0,
141  /**
142  * TODO More documentation
143  */
145  /**
146  * Indicates that the terminal is in 'Ansi' mode.
147  * TODO: More documentation
148  */
150  /**
151  * TODO More documentation
152  */
154  /**
155  * Indicates that the alternate screen ( typically used by interactive programs
156  * such as screen or vim ) is active
157  */
159  /** Indicates that any of the modifier keys is active. */
161  };
162  Q_DECLARE_FLAGS(States,State)
163 
164  /**
165  * This enum describes commands which are associated with particular key sequences.
166  */
167  enum Command
168  {
169  /** Indicates that no command is associated with this command sequence */
171  /** TODO Document me */
173  /** Scroll the terminal display up one page */
175  /** Scroll the terminal display down one page */
177  /** Scroll the terminal display up one line */
179  /** Scroll the terminal display down one line */
181  /** Toggles scroll lock mode */
183  /** Echos the operating system specific erase character. */
185  };
186  Q_DECLARE_FLAGS(Commands,Command)
187 
188  /**
189  * Represents an association between a key sequence pressed by the user
190  * and the character sequence and commands associated with it for a particular
191  * KeyboardTranslator.
192  */
193  class Entry
194  {
195  public:
196  /**
197  * Constructs a new entry for a keyboard translator.
198  */
199  Entry();
200 
201  /**
202  * Returns true if this entry is null.
203  * This is true for newly constructed entries which have no properties set.
204  */
205  bool isNull() const;
206 
207  /** Returns the commands associated with this entry */
208  Command command() const;
209  /** Sets the command associated with this entry. */
210  void setCommand(Command command);
211 
212  /**
213  * Returns the character sequence associated with this entry, optionally replacing
214  * wildcard '*' characters with numbers to indicate the keyboard modifiers being pressed.
215  *
216  * TODO: The numbers used to replace '*' characters are taken from the Konsole/KDE 3 code.
217  * Document them.
218  *
219  * @param expandWildCards Specifies whether wild cards (occurrences of the '*' character) in
220  * the entry should be replaced with a number to indicate the modifier keys being pressed.
221  *
222  * @param modifiers The keyboard modifiers being pressed.
223  */
224  QByteArray text(bool expandWildCards = false,
225  Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
226 
227  /** Sets the character sequence associated with this entry */
228  void setText(const QByteArray& text);
229 
230  /**
231  * Returns the character sequence associated with this entry,
232  * with any non-printable characters replaced with escape sequences.
233  *
234  * eg. \\E for Escape, \\t for tab, \\n for new line.
235  *
236  * @param expandWildCards See text()
237  * @param modifiers See text()
238  */
239  QByteArray escapedText(bool expandWildCards = false,
240  Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
241 
242  /** Returns the character code ( from the Qt::Key enum ) associated with this entry */
243  int keyCode() const;
244  /** Sets the character code associated with this entry */
245  void setKeyCode(int keyCode);
246 
247  /**
248  * Returns a bitwise-OR of the enabled keyboard modifiers associated with this entry.
249  * If a modifier is set in modifierMask() but not in modifiers(), this means that the entry
250  * only matches when that modifier is NOT pressed.
251  *
252  * If a modifier is not set in modifierMask() then the entry matches whether the modifier
253  * is pressed or not.
254  */
255  Qt::KeyboardModifiers modifiers() const;
256 
257  /** Returns the keyboard modifiers which are valid in this entry. See modifiers() */
258  Qt::KeyboardModifiers modifierMask() const;
259 
260  /** See modifiers() */
261  void setModifiers( Qt::KeyboardModifiers modifiers );
262  /** See modifierMask() and modifiers() */
263  void setModifierMask( Qt::KeyboardModifiers modifiers );
264 
265  /**
266  * Returns a bitwise-OR of the enabled state flags associated with this entry.
267  * If flag is set in stateMask() but not in state(), this means that the entry only
268  * matches when the terminal is NOT in that state.
269  *
270  * If a state is not set in stateMask() then the entry matches whether the terminal
271  * is in that state or not.
272  */
273  States state() const;
274 
275  /** Returns the state flags which are valid in this entry. See state() */
276  States stateMask() const;
277 
278  /** See state() */
279  void setState( States state );
280  /** See stateMask() */
281  void setStateMask( States mask );
282 
283  /**
284  * Returns the key code and modifiers associated with this entry
285  * as a QKeySequence
286  */
287  //QKeySequence keySequence() const;
288 
289  /**
290  * Returns this entry's conditions ( ie. its key code, modifier and state criteria )
291  * as a string.
292  */
293  QString conditionToString() const;
294 
295  /**
296  * Returns this entry's result ( ie. its command or character sequence )
297  * as a string.
298  *
299  * @param expandWildCards See text()
300  * @param modifiers See text()
301  */
302  QString resultToString(bool expandWildCards = false,
303  Qt::KeyboardModifiers modifiers = Qt::NoModifier) const;
304 
305  /**
306  * Returns true if this entry matches the given key sequence, specified
307  * as a combination of @p keyCode , @p modifiers and @p state.
308  */
309  bool matches( int keyCode ,
310  Qt::KeyboardModifiers modifiers ,
311  States flags ) const;
312 
313  bool operator==(const Entry& rhs) const;
314 
315  private:
316  void insertModifier( QString& item , int modifier ) const;
317  void insertState( QString& item , int state ) const;
318  QByteArray unescape(const QByteArray& text) const;
319 
320  int _keyCode;
321  Qt::KeyboardModifiers _modifiers;
322  Qt::KeyboardModifiers _modifierMask;
323  States _state;
324  States _stateMask;
325 
327  QByteArray _text;
328  };
329 
330  /** Constructs a new keyboard translator with the given @p name */
331  KeyboardTranslator(const QString& name);
332 
333  //KeyboardTranslator(const KeyboardTranslator& other);
334 
335  /** Returns the name of this keyboard translator */
336  QString name() const;
337 
338  /** Sets the name of this keyboard translator */
339  void setName(const QString& name);
340 
341  /** Returns the descriptive name of this keyboard translator */
342  QString description() const;
343 
344  /** Sets the descriptive name of this keyboard translator */
345  void setDescription(const QString& description);
346 
347  /**
348  * Looks for an entry in this keyboard translator which matches the given
349  * key code, keyboard modifiers and state flags.
350  *
351  * Returns the matching entry if found or a null Entry otherwise ( ie.
352  * entry.isNull() will return true )
353  *
354  * @param keyCode A key code from the Qt::Key enum
355  * @param modifiers A combination of modifiers
356  * @param state Optional flags which specify the current state of the terminal
357  */
358  Entry findEntry(int keyCode ,
359  Qt::KeyboardModifiers modifiers ,
360  States state = NoState) const;
361 
362  /**
363  * Adds an entry to this keyboard translator's table. Entries can be looked up according
364  * to their key sequence using findEntry()
365  */
366  void addEntry(const Entry& entry);
367 
368  /**
369  * Replaces an entry in the translator. If the @p existing entry is null,
370  * then this is equivalent to calling addEntry(@p replacement)
371  */
372  void replaceEntry(const Entry& existing , const Entry& replacement);
373 
374  /**
375  * Removes an entry from the table.
376  */
377  void removeEntry(const Entry& entry);
378 
379  /** Returns a list of all entries in the translator. */
380  QList<Entry> entries() const;
381 
382 private:
383 
384  QHash<int,Entry> _entries; // entries in this keyboard translation,
385  // entries are indexed according to
386  // their keycode
387  QString _name;
388  QString _description;
389 };
390 Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::States)
391 Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands)
392 
393 /**
394  * Parses the contents of a Keyboard Translator (.keytab) file and
395  * returns the entries found in it.
396  *
397  * Usage example:
398  *
399  * @code
400  * QFile source( "/path/to/keytab" );
401  * source.open( QIODevice::ReadOnly );
402  *
403  * KeyboardTranslator* translator = new KeyboardTranslator( "name-of-translator" );
404  *
405  * KeyboardTranslatorReader reader(source);
406  * while ( reader.hasNextEntry() )
407  * translator->addEntry(reader.nextEntry());
408  *
409  * source.close();
410  *
411  * if ( !reader.parseError() )
412  * {
413  * // parsing succeeded, do something with the translator
414  * }
415  * else
416  * {
417  * // parsing failed
418  * }
419  * @endcode
420  */
422 {
423 public:
424  /** Constructs a new reader which parses the given @p source */
425  KeyboardTranslatorReader( QIODevice* source );
426 
427  /**
428  * Returns the description text.
429  * TODO: More documentation
430  */
431  QString description() const;
432 
433  /** Returns true if there is another entry in the source stream */
434  bool hasNextEntry();
435  /** Returns the next entry found in the source stream */
436  KeyboardTranslator::Entry nextEntry();
437 
438  /**
439  * Returns true if an error occurred whilst parsing the input or
440  * false if no error occurred.
441  */
442  bool parseError();
443 
444  /**
445  * Parses a condition and result string for a translator entry
446  * and produces a keyboard translator entry.
447  *
448  * The condition and result strings are in the same format as in
449  */
450  static KeyboardTranslator::Entry createEntry( const QString& condition ,
451  const QString& result );
452 private:
453  struct Token
454  {
455  enum Type
456  {
462  OutputText
463  };
465  QString text;
466  };
467  QList<Token> tokenize(const QString&);
468  void readNext();
469  bool decodeSequence(const QString& ,
470  int& keyCode,
471  Qt::KeyboardModifiers& modifiers,
472  Qt::KeyboardModifiers& modifierMask,
473  KeyboardTranslator::States& state,
474  KeyboardTranslator::States& stateFlags);
475 
476  static bool parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier);
477  static bool parseAsStateFlag(const QString& item , KeyboardTranslator::State& state);
478  static bool parseAsKeyCode(const QString& item , int& keyCode);
479  static bool parseAsCommand(const QString& text , KeyboardTranslator::Command& command);
480 
481  QIODevice* _source;
482  QString _description;
484  bool _hasNext;
485 };
486 
487 /** Writes a keyboard translation to disk. */
489 {
490 public:
491  /**
492  * Constructs a new writer which saves data into @p destination.
493  * The caller is responsible for closing the device when writing is complete.
494  */
495  KeyboardTranslatorWriter(QIODevice* destination);
497 
498  /**
499  * Writes the header for the keyboard translator.
500  * @param description Description of the keyboard translator.
501  */
502  void writeHeader( const QString& description );
503  /** Writes a translator entry. */
504  void writeEntry( const KeyboardTranslator::Entry& entry );
505 
506 private:
507  QIODevice* _destination;
508  QTextStream* _writer;
509 };
510 
511 /**
512  * Manages the keyboard translations available for use by terminal sessions,
513  * see KeyboardTranslator.
514  */
516 {
517 public:
518  /**
519  * Constructs a new KeyboardTranslatorManager and loads the list of
520  * available keyboard translations.
521  *
522  * The keyboard translations themselves are not loaded until they are
523  * first requested via a call to findTranslator()
524  */
527 
528  /**
529  * Adds a new translator. If a translator with the same name
530  * already exists, it will be replaced by the new translator.
531  *
532  * TODO: More documentation.
533  */
534  void addTranslator(KeyboardTranslator* translator);
535 
536  /**
537  * Deletes a translator. Returns true on successful deletion or false otherwise.
538  *
539  * TODO: More documentation
540  */
541  bool deleteTranslator(const QString& name);
542 
543  /** Returns the default translator for Konsole. */
545 
546  /**
547  * Returns the keyboard translator with the given name or 0 if no translator
548  * with that name exists.
549  *
550  * The first time that a translator with a particular name is requested,
551  * the on-disk .keyboard file is loaded and parsed.
552  */
553  const KeyboardTranslator* findTranslator(const QString& name);
554  /**
555  * Returns a list of the names of available keyboard translators.
556  *
557  * The first time this is called, a search for available
558  * translators is started.
559  */
561 
562  /** Returns the global KeyboardTranslatorManager instance. */
564 
565 private:
566  static const char* defaultTranslatorText;
567 
568  void findTranslators(); // locate the available translators
569  KeyboardTranslator* loadTranslator(const QString& name); // loads the translator
570  // with the given name
571  KeyboardTranslator* loadTranslator(QIODevice* device,const QString& name);
572 
573  bool saveTranslator(const KeyboardTranslator* translator);
574  QString findTranslatorPath(const QString& name);
575 
576  QHash<QString,KeyboardTranslator*> _translators; // maps translator-name -> KeyboardTranslator
577  // instance
579 };
580 
581 inline int KeyboardTranslator::Entry::keyCode() const { return _keyCode; }
582 inline void KeyboardTranslator::Entry::setKeyCode(int keyCode) { _keyCode = keyCode; }
583 
584 inline void KeyboardTranslator::Entry::setModifiers( Qt::KeyboardModifiers modifier )
585 {
586  _modifiers = modifier;
587 }
588 inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifiers() const { return _modifiers; }
589 
590 inline void KeyboardTranslator::Entry::setModifierMask( Qt::KeyboardModifiers mask )
591 {
592  _modifierMask = mask;
593 }
594 inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifierMask() const { return _modifierMask; }
595 
597 {
598  return ( *this == Entry() );
599 }
600 
602 {
603  _command = command;
604 }
606 
607 inline void KeyboardTranslator::Entry::setText( const QByteArray& text )
608 {
609  _text = unescape(text);
610 }
611 inline int oneOrZero(int value)
612 {
613  return value ? 1 : 0;
614 }
615 inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards,Qt::KeyboardModifiers modifiers) const
616 {
617  QByteArray expandedText = _text;
618 
619  if (expandWildCards)
620  {
621  int modifierValue = 1;
622  modifierValue += oneOrZero(modifiers & Qt::ShiftModifier);
623  modifierValue += oneOrZero(modifiers & Qt::AltModifier) << 1;
624  modifierValue += oneOrZero(modifiers & Qt::ControlModifier) << 2;
625 
626  for (int i=0;i<_text.length();i++)
627  {
628  if (expandedText[i] == '*')
629  expandedText[i] = '0' + modifierValue;
630  }
631  }
632 
633  return expandedText;
634 }
635 
637 {
638  _state = state;
639 }
640 inline KeyboardTranslator::States KeyboardTranslator::Entry::state() const { return _state; }
641 
642 inline void KeyboardTranslator::Entry::setStateMask( States stateMask )
643 {
644  _stateMask = stateMask;
645 }
646 inline KeyboardTranslator::States KeyboardTranslator::Entry::stateMask() const { return _stateMask; }
647 
648 
649 #endif // KEYBOARDTRANSLATOR_H
650