From cbbb5aad0a5f303af49237e9e7d39418fefd8a5c Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Sun, 22 Jul 2018 23:07:49 +0200 Subject: [PATCH] Added unit test for FKeyboard --- ChangeLog | 3 + README.md | 29 +-- doc/class-diagram.txt | 30 +-- include/final/final.h | 3 +- include/final/fkeyboard.h | 91 ++++---- include/final/fmouse.h | 2 + include/final/fterm.h | 10 +- src/fapplication.cpp | 2 +- src/fkey_map.cpp | 4 + src/fkeyboard.cpp | 55 +++-- src/fterm.cpp | 1 - src/test/Makefile.am | 3 + src/test/Makefile.in | 40 +++- src/test/fkeyboard-test.cpp | 455 ++++++++++++++++++++++++++++++++++++ 14 files changed, 623 insertions(+), 105 deletions(-) create mode 100644 src/test/fkeyboard-test.cpp diff --git a/ChangeLog b/ChangeLog index 9ff2d6c0..85828dc5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2017-07-22 Markus Gans + * Added unit test for FKeyboard + 2017-07-15 Markus Gans * Keyboard functions are now in a separate class * Fix Parameter passing in term::init_OptiAttr diff --git a/README.md b/README.md index a8ac1fef..e6f59054 100644 --- a/README.md +++ b/README.md @@ -117,17 +117,20 @@ printf(...) Class digramm -------------
-              1┌──────────────┐                 ┌───────────┐
-   ┌-----------┤ FTermFreeBSD │            ┌────┤ FKeyEvent │
+              1┌──────────────┐
+   ┌-----------┤ FTermFreeBSD │
+   :           └──────────────┘
+   :          1┌──────────────┐                 ┌───────────┐
+   ┌-----------┤ FTermOpenBSD │            ┌────┤ FKeyEvent │
    :           └──────────────┘            │    └───────────┘
-   :          1┌──────────────┐            │    ┌─────────────┐
-   ┌-----------┤ FTermOpenBSD │            ├────┤ FMouseEvent │
-   :           └──────────────┘            │    └─────────────┘
    :          1┌────────────────┐          │    ┌─────────────┐
-   ┌-----------┤ FTermDetection │          ├────┤ FWheelEvent │
+   ┌-----------┤ FTermDetection │          ├────┤ FMouseEvent │
    :           └────────────────┘          │    └─────────────┘
    :          1┌────────────────┐          │    ┌─────────────┐
-   ┌-----------┤ FTermcapQuirks │          ├────┤ FFocusEvent │
+   ┌-----------┤ FTermcapQuirks │          ├────┤ FWheelEvent │
+   :           └────────────────┘          │    └─────────────┘
+   :          1┌────────────────┐          │    ┌─────────────┐
+   ┌-----------┤ FTermXTerminal │          ├────┤ FFocusEvent │
    :           └────────────────┘          │    └─────────────┘
    :          1┌──────────┐                │    ┌─────────────┐
    ┌-----------┤ FTermcap │    ┌────────┐  ├────┤ FAccelEvent │
@@ -135,17 +138,17 @@ Class digramm
    :          1┌──────────┐    └───┬────┘  │    ┌──────────────┐
    ┌-----------┤ FTermios │        :1      ├────┤ FResizeEvent │
    :           └──────────┘        :       │    └──────────────┘
-   :          1┌────────────────┐  :       │    ┌────────────┐
-   ┌-----------┤ FTermXTerminal │  :       ├────┤ FShowEvent │
-   :           └────────────────┘  :       │    └────────────┘
    :          1┌───────────────┐   :       │    ┌────────────┐
-   ┌-----------┤ FColorPalette │   :       ├────┤ FHideEvent │
+   ┌-----------┤ FColorPalette │   :       ├────┤ FShowEvent │
    :           └───────────────┘   :       │    └────────────┘
+   :          1┌───────────┐       :       │    ┌────────────┐
+   ┌-----------┤ FOptiMove │       :       ├────┤ FHideEvent │
+   :           └───────────┘       :       │    └────────────┘
    :          1┌───────────┐       :       │    ┌─────────────┐
-   ┌-----------┤ FOptiMove │       :       ├────┤ FCloseEvent │
+   ┌-----------┤ FOptiAttr │       :       ├────┤ FCloseEvent │
    :           └───────────┘       :       │    └─────────────┘
    :          1┌───────────┐       :       │    ┌─────────────┐
-   ┌-----------┤ FOptiAttr │       :       └────┤ FTimerEvent │
+   ┌-----------┤ FKeyboard │       :       └────┤ FTimerEvent │
    :           └───────────┘       :            └─────────────┘
    :          1┌───────────────┐   :
    ┌-----------┤ FMouseControl │   :            ┌──────────────┐
diff --git a/doc/class-diagram.txt b/doc/class-diagram.txt
index 6792b81b..ef38bfbe 100644
--- a/doc/class-diagram.txt
+++ b/doc/class-diagram.txt
@@ -1,18 +1,20 @@
 ══════════════════════════════════════════════════════════════════════════════
                                  Class digramm
 ══════════════════════════════════════════════════════════════════════════════
-
-              1┌──────────────┐                 ┌───────────┐
-   ┌-----------┤ FTermFreeBSD │            ┌────┤ FKeyEvent │
+              1┌──────────────┐
+   ┌-----------┤ FTermFreeBSD │
+   :           └──────────────┘
+   :          1┌──────────────┐                 ┌───────────┐
+   ┌-----------┤ FTermOpenBSD │            ┌────┤ FKeyEvent │
    :           └──────────────┘            │    └───────────┘
-   :          1┌──────────────┐            │    ┌─────────────┐
-   ┌-----------┤ FTermOpenBSD │            ├────┤ FMouseEvent │
-   :           └──────────────┘            │    └─────────────┘
    :          1┌────────────────┐          │    ┌─────────────┐
-   ┌-----------┤ FTermDetection │          ├────┤ FWheelEvent │
+   ┌-----------┤ FTermDetection │          ├────┤ FMouseEvent │
    :           └────────────────┘          │    └─────────────┘
    :          1┌────────────────┐          │    ┌─────────────┐
-   ┌-----------┤ FTermcapQuirks │          ├────┤ FFocusEvent │
+   ┌-----------┤ FTermcapQuirks │          ├────┤ FWheelEvent │
+   :           └────────────────┘          │    └─────────────┘
+   :          1┌────────────────┐          │    ┌─────────────┐
+   ┌-----------┤ FTermXTerminal │          ├────┤ FFocusEvent │
    :           └────────────────┘          │    └─────────────┘
    :          1┌──────────┐                │    ┌─────────────┐
    ┌-----------┤ FTermcap │    ┌────────┐  ├────┤ FAccelEvent │
@@ -20,17 +22,17 @@
    :          1┌──────────┐    └───┬────┘  │    ┌──────────────┐
    ┌-----------┤ FTermios │        :1      ├────┤ FResizeEvent │
    :           └──────────┘        :       │    └──────────────┘
-   :          1┌────────────────┐  :       │    ┌────────────┐
-   ┌-----------┤ FTermXTerminal │  :       ├────┤ FShowEvent │
-   :           └────────────────┘  :       │    └────────────┘
    :          1┌───────────────┐   :       │    ┌────────────┐
-   ┌-----------┤ FColorPalette │   :       ├────┤ FHideEvent │
+   ┌-----------┤ FColorPalette │   :       ├────┤ FShowEvent │
    :           └───────────────┘   :       │    └────────────┘
+   :          1┌───────────┐       :       │    ┌────────────┐
+   ┌-----------┤ FOptiMove │       :       ├────┤ FHideEvent │
+   :           └───────────┘       :       │    └────────────┘
    :          1┌───────────┐       :       │    ┌─────────────┐
-   ┌-----------┤ FOptiMove │       :       ├────┤ FCloseEvent │
+   ┌-----------┤ FOptiAttr │       :       ├────┤ FCloseEvent │
    :           └───────────┘       :       │    └─────────────┘
    :          1┌───────────┐       :       │    ┌─────────────┐
-   ┌-----------┤ FOptiAttr │       :       └────┤ FTimerEvent │
+   ┌-----------┤ FKeyboard │       :       └────┤ FTimerEvent │
    :           └───────────┘       :            └─────────────┘
    :          1┌───────────────┐   :
    ┌-----------┤ FMouseControl │   :            ┌──────────────┐
diff --git a/include/final/final.h b/include/final/final.h
index 047f0436..21bdd84e 100644
--- a/include/final/final.h
+++ b/include/final/final.h
@@ -4,7 +4,7 @@
 *                                                                      *
 * This file is part of the Final Cut widget toolkit                    *
 *                                                                      *
-* Copyright 2014-2017 Markus Gans                                      *
+* Copyright 2014-2018 Markus Gans                                      *
 *                                                                      *
 * The Final Cut is free software; you can redistribute it and/or       *
 * modify it under the terms of the GNU Lesser General Public License   *
@@ -26,6 +26,7 @@
 
 #define USE_FINAL_H
 
+#include 
 #include 
 #include 
 #include 
diff --git a/include/final/fkeyboard.h b/include/final/fkeyboard.h
index cb92bad8..089d4d3f 100644
--- a/include/final/fkeyboard.h
+++ b/include/final/fkeyboard.h
@@ -84,40 +84,42 @@ class FKeyboard
     FKeyboard();
 
     // Destructor
-    ~FKeyboard();
+    virtual ~FKeyboard();
 
     // Accessors
-    int           getKey();
-    const FString getKeyName (int);
-    char*         getKeyBuffer();
-    int           getKeyBufferSize();
-    timeval*      getKeyPressedTime();
+    virtual const char* getClassName() const;
+    int                 getKey();
+    const FString       getKeyName (int);
+    char*               getKeyBuffer();
+    int                 getKeyBufferSize();
+    timeval*            getKeyPressedTime();
 
     // Mutators
-    void          setTermcapMap (fc::fkeymap*);
-    void          setKeypressTimeout (const long);
-    void          enableUTF8();
-    void          disableUTF8();
-    void          enableMouseSequences();
-    void          disableMouseSequences();
+    void                setTermcapMap (fc::fkeymap*);
+    void                setKeypressTimeout (const long);
+    void                enableUTF8();
+    void                disableUTF8();
+    void                enableMouseSequences();
+    void                disableMouseSequences();
 
 #if defined(__linux__)
-    void          setFTermLinux (FTermLinux*);
+    void                setFTermLinux (FTermLinux*);
 #endif
 
-    void          setPressCommand (FKeyboardCommand);
-    void          setReleaseCommand (FKeyboardCommand);
-    void          setEscPressedCommand (FKeyboardCommand);
+    void                setPressCommand (FKeyboardCommand);
+    void                setReleaseCommand (FKeyboardCommand);
+    void                setEscPressedCommand (FKeyboardCommand);
 
     // Inquiry
-    bool          isInputDataPending();
+    bool                isInputDataPending();
 
     // Methods
-    bool&         unprocessedInput();
-    bool          isKeyPressed();
-    void          emptyKeyBufferOnTimeout();
-    void          fetchKeyCode();
-    void          escapeKeyHandling();
+    bool&               unprocessedInput();
+    bool                isKeyPressed();
+    void                clearKeyBuffer();
+    void                clearKeyBufferOnTimeout();
+    void                fetchKeyCode();
+    void                escapeKeyHandling();
 
   private:
     // Constants
@@ -130,28 +132,28 @@ class FKeyboard
     FKeyboard& operator = (const FKeyboard&);
 
     // Accessors
-    int           getMouseProtocolKey();
-    int           getTermcapKey();
-    int           getMetaKey();
-    int           getSingleKey();
+    int                 getMouseProtocolKey();
+    int                 getTermcapKey();
+    int                 getMetaKey();
+    int                 getSingleKey();
 
     // Mutators
-    bool          setNonBlockingInput (bool);
-    bool          setNonBlockingInput();
-    bool          unsetNonBlockingInput();
+    bool                setNonBlockingInput (bool);
+    bool                setNonBlockingInput();
+    bool                unsetNonBlockingInput();
 
     // Inquiry
-    static bool   isKeypressTimeout (timeval*);
+    static bool         isKeypressTimeout();
 
     // Methods
-    int           UTF8decode (const char[]);
-    ssize_t       readKey();
-    void          parseKeyBuffer();
-    int           parseKeyString();
-    int 	        keyCorrection (const int&);
-    void          keyPressed();
-    void          keyReleased();
-    void          escapeKeyPressed();
+    int                 UTF8decode (const char[]);
+    ssize_t             readKey();
+    void                parseKeyBuffer();
+    int                 parseKeyString();
+    int                 keyCorrection (const int&);
+    void                keyPressed();
+    void                keyReleased();
+    void                escapeKeyPressed();
 
     // Data Members
     int              key;
@@ -170,9 +172,8 @@ class FKeyboard
     FKeyboardCommand keyreleased_cmd;
     FKeyboardCommand escape_key_cmd;
 
-    struct timeval   time_keypressed;
+    static timeval   time_keypressed;
     fc::fkeymap*     termcap_map;
-    //void*           termcap_map;
 
 #if defined(__linux__)
     #undef linux
@@ -182,6 +183,10 @@ class FKeyboard
 #pragma pack(pop)
 
 // FKeyboard inline functions
+//----------------------------------------------------------------------
+inline const char* FKeyboard::getClassName() const
+{ return "FKeyboard"; }
+
 //----------------------------------------------------------------------
 inline int FKeyboard::getKey()
 { return key; }
@@ -194,7 +199,7 @@ inline int FKeyboard::getKeyBufferSize()
 { return fifo_buf_size; }
 
 //----------------------------------------------------------------------
-inline struct timeval* FKeyboard::getKeyPressedTime()
+inline timeval* FKeyboard::getKeyPressedTime()
 { return &time_keypressed; }
 
 //----------------------------------------------------------------------
@@ -235,10 +240,6 @@ inline void FKeyboard::setReleaseCommand (FKeyboardCommand cmd)
 inline void FKeyboard::setEscPressedCommand (FKeyboardCommand cmd)
 { escape_key_cmd = cmd; }
 
-//----------------------------------------------------------------------
-inline bool FKeyboard::isKeypressTimeout (timeval* time)
-{ return FObject::isTimeout (time, key_timeout); }
-
 //----------------------------------------------------------------------
 inline bool FKeyboard::isInputDataPending()
 { return input_data_pending; }
diff --git a/include/final/fmouse.h b/include/final/fmouse.h
index 2ae84c2b..ab088c5a 100644
--- a/include/final/fmouse.h
+++ b/include/final/fmouse.h
@@ -515,6 +515,8 @@ class FMouseControl
 };
 #pragma pack(pop)
 
+// FMouseControl inline functions
+//----------------------------------------------------------------------
 inline const char* FMouseControl::getClassName() const
 { return "FMouseControl"; }
 
diff --git a/include/final/fterm.h b/include/final/fterm.h
index 1a39838e..b8c51b6b 100644
--- a/include/final/fterm.h
+++ b/include/final/fterm.h
@@ -71,6 +71,10 @@
  *           :- - - -▕ FKeyboard ▏
  *           :       ▕▁▁▁▁▁▁▁▁▁▁▁▏
  *           :
+ *           :      1▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏
+ *           :- - - -▕ FMouseControl ▏
+ *           :       ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏
+ *           :
  *           :      *▕▔▔▔▔▔▔▔▔▔▏
  *           :- - - -▕ FString ▏
  *           :       ▕▁▁▁▁▁▁▁▁▁▏
@@ -132,6 +136,7 @@
 
 #include "final/fc.h"
 #include "final/fcolorpalette.h"
+#include "final/fkey_map.h"
 #include "final/fkeyboard.h"
 #include "final/fmouse.h"
 #include "final/fobject.h"
@@ -310,11 +315,6 @@ class FTerm
 
     // Accessors
     FOptiMove*            getFOptiMove();
-    static uInt           getEraseCharsLength();
-    static uInt           getRepeatCharLength();
-    static uInt           getClrBolLength();
-    static uInt           getClrEolLength();
-    static uInt           getCursorAddressLength();
 
     // Methods
     static void           initScreenSettings();
diff --git a/src/fapplication.cpp b/src/fapplication.cpp
index 04343e32..93dfa9f9 100644
--- a/src/fapplication.cpp
+++ b/src/fapplication.cpp
@@ -680,7 +680,7 @@ void FApplication::processKeyboardEvent()
 
   findKeyboardWidget();
   flush_out();
-  keyboard->emptyKeyBufferOnTimeout();
+  keyboard->clearKeyBufferOnTimeout();
 
   if ( isKeyPressed() )
     keyboard->fetchKeyCode();
diff --git a/src/fkey_map.cpp b/src/fkey_map.cpp
index a3ac8d58..d81207f7 100644
--- a/src/fkey_map.cpp
+++ b/src/fkey_map.cpp
@@ -457,6 +457,7 @@ keyname FkeyName[] =
   { fc::Fckey_y                   , "Ctrl+Y" },
   { fc::Fckey_z                   , "Ctrl+Z" },
   { fc::Fkey_escape               , "Esc" },        // Ctrl+[
+  { fc::Fkey_escape_mintty        , "Esc" },
   { fc::Fckey_backslash           , "Ctrl+\\" },
   { fc::Fckey_right_square_bracket, "Ctrl+]" },
   { fc::Fckey_caret               , "Ctrl+^" },
@@ -813,6 +814,9 @@ keyname FkeyName[] =
   { fc::Fmkey_vertical_bar        , "Meta+|" },
   { fc::Fmkey_right_curly_bracket , "Meta+}" },
   { fc::Fmkey_tilde               , "Meta+~" },
+  { fc::Fkey_mouse                , "xterm mouse" },
+  { fc::Fkey_extended_mouse       , "SGR extended mouse" },
+  { fc::Fkey_urxvt_mouse          , "urxvt mouse extension" },
   { 0                             , "\0" }
 };
 
diff --git a/src/fkeyboard.cpp b/src/fkeyboard.cpp
index 3b5f13de..62048138 100644
--- a/src/fkeyboard.cpp
+++ b/src/fkeyboard.cpp
@@ -28,6 +28,7 @@
 
 // static class attributes
 long FKeyboard::key_timeout = 100000;  // 100 ms (default timeout for keypress)
+struct timeval FKeyboard::time_keypressed;
 
 #if defined(__linux__)
   FTermLinux* FKeyboard::linux = 0;
@@ -75,7 +76,6 @@ FKeyboard::FKeyboard()
   , keypressed_cmd()
   , keyreleased_cmd()
   , escape_key_cmd()
-  , time_keypressed()
   , termcap_map(0)
 {
   // Initialize keyboard values
@@ -150,16 +150,23 @@ bool FKeyboard::isKeyPressed()
 }
 
 //----------------------------------------------------------------------
-void FKeyboard::emptyKeyBufferOnTimeout()
+void FKeyboard::clearKeyBuffer()
+{
+  // Empty the buffer
+
+  fifo_offset = 0;
+  key = 0;
+  std::fill_n (fifo_buf, fifo_buf_size, '\0');
+  fifo_in_use = false;
+}
+
+//----------------------------------------------------------------------
+void FKeyboard::clearKeyBufferOnTimeout()
 {
   // Empty the buffer on timeout
-  if ( fifo_in_use && isKeypressTimeout(&time_keypressed) )
-  {
-    fifo_offset = 0;
-    key = 0;
-    std::fill_n (fifo_buf, fifo_buf_size, '\0');
-    fifo_in_use = false;
-  }
+
+  if ( fifo_in_use && isKeypressTimeout() )
+    clearKeyBuffer();
 }
 
 //----------------------------------------------------------------------
@@ -172,7 +179,7 @@ void FKeyboard::escapeKeyHandling()
     && fifo_offset == 1
     && fifo_buf[0] == 0x1b
     && fifo_buf[1] == 0x00
-    && isKeypressTimeout(&time_keypressed) )
+    && isKeypressTimeout() )
   {
     fifo_offset = 0;
     fifo_buf[0] = 0x00;
@@ -216,13 +223,15 @@ inline int FKeyboard::getMouseProtocolKey()
 inline int FKeyboard::getTermcapKey()
 {
   // Looking for termcap key strings in the buffer
+
   assert ( fifo_buf_size > 0 );
 
-  //for (int i = 0; fc::Fkey[i].tname[0] != 0; i++)
+  if ( ! termcap_map )
+    return -1;
+
   fc::fkeymap* keymap = reinterpret_cast(termcap_map);
   for (int i = 0; keymap[i].tname[0] != 0; i++)
   {
-    //char* k = fc::Fkey[i].string;
     char* k = keymap[i].string;
     register int len = ( k ) ? int(std::strlen(k)) : 0;
 
@@ -248,6 +257,7 @@ inline int FKeyboard::getTermcapKey()
 inline int FKeyboard::getMetaKey()
 {
   // Looking for meta key strings in the buffer
+
   assert ( fifo_buf_size > 0 );
 
   for (int i = 0; fc::Fmetakey[i].string[0] != 0; i++)
@@ -263,7 +273,7 @@ inline int FKeyboard::getMetaKey()
                       || fifo_buf[1] == '['
                       || fifo_buf[1] == ']' ) )
       {
-        if ( ! isKeypressTimeout(&time_keypressed) )
+        if ( ! isKeypressTimeout() )
           return NEED_MORE_DATA;
       }
 
@@ -284,6 +294,8 @@ inline int FKeyboard::getMetaKey()
 //----------------------------------------------------------------------
 inline int FKeyboard::getSingleKey()
 {
+  // Looking for single key code in the buffer
+
   register uChar firstchar = uChar(fifo_buf[0]);
   int keycode, n, len;
   len = 1;
@@ -346,6 +358,12 @@ bool FKeyboard::setNonBlockingInput (bool on)
   return non_blocking_stdin;
 }
 
+//----------------------------------------------------------------------
+bool FKeyboard::isKeypressTimeout()
+{
+  return FObject::isTimeout (&time_keypressed, key_timeout);
+}
+
 //----------------------------------------------------------------------
 int FKeyboard::UTF8decode (const char utf8[])
 {
@@ -401,7 +419,7 @@ inline ssize_t FKeyboard::readKey()
 }
 
 //----------------------------------------------------------------------
-inline void FKeyboard::parseKeyBuffer()
+void FKeyboard::parseKeyBuffer()
 {
   register ssize_t bytesread;
   FObject::getCurrentTime (&time_keypressed);
@@ -420,7 +438,7 @@ inline void FKeyboard::parseKeyBuffer()
     }
 
     // Read the rest from the fifo buffer
-    while ( ! isKeypressTimeout(&time_keypressed)
+    while ( ! isKeypressTimeout()
          && fifo_offset > 0
          && key != NEED_MORE_DATA )
     {
@@ -431,6 +449,11 @@ inline void FKeyboard::parseKeyBuffer()
         keyPressed();
 
       fifo_offset = int(std::strlen(fifo_buf));
+
+      if ( key == fc::Fkey_mouse
+        || key == fc::Fkey_extended_mouse
+        || key == fc::Fkey_urxvt_mouse )
+        break;
     }
 
     // Send key up event
@@ -465,7 +488,7 @@ int FKeyboard::parseKeyString()
     if ( keycode > 0 )
       return keycode;
 
-    if ( ! isKeypressTimeout(&time_keypressed) )
+    if ( ! isKeypressTimeout() )
       return NEED_MORE_DATA;
   }
 
diff --git a/src/fterm.cpp b/src/fterm.cpp
index 699d4e8e..b522707c 100644
--- a/src/fterm.cpp
+++ b/src/fterm.cpp
@@ -27,7 +27,6 @@
 
 #include "final/fterm.h"
 #include "final/fcharmap.h"
-#include "final/fkey_map.h"
 #include "final/ftcap_map.h"
 
 // global FTerm object
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
index 4351469a..7e8cc6b1 100644
--- a/src/test/Makefile.am
+++ b/src/test/Makefile.am
@@ -9,6 +9,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -Wall -Werror
 noinst_PROGRAMS = \
 	fobject_test \
 	fmouse_test \
+	fkeyboard_test \
 	foptimove_test \
 	foptiattr_test \
 	fstring_test \
@@ -17,6 +18,7 @@ noinst_PROGRAMS = \
 
 fobject_test_SOURCES = fobject-test.cpp
 fmouse_test_SOURCES = fmouse-test.cpp
+fkeyboard_test_SOURCES = fkeyboard-test.cpp
 foptimove_test_SOURCES = foptimove-test.cpp
 foptiattr_test_SOURCES = foptiattr-test.cpp
 fstring_test_SOURCES = fstring-test.cpp
@@ -25,6 +27,7 @@ frect_test_SOURCES = frect-test.cpp
 
 TESTS = fobject_test \
 	fmouse_test \
+	fkeyboard_test \
 	foptimove_test \
 	foptiattr_test \
 	fstring_test \
diff --git a/src/test/Makefile.in b/src/test/Makefile.in
index e174dde2..4a69d9ab 100644
--- a/src/test/Makefile.in
+++ b/src/test/Makefile.in
@@ -84,11 +84,13 @@ build_triplet = @build@
 host_triplet = @host@
 @CPPUNIT_TEST_TRUE@noinst_PROGRAMS = fobject_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	fmouse_test$(EXEEXT) \
+@CPPUNIT_TEST_TRUE@	fkeyboard_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	foptimove_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	foptiattr_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	fstring_test$(EXEEXT) fpoint_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	frect_test$(EXEEXT)
 @CPPUNIT_TEST_TRUE@TESTS = fobject_test$(EXEEXT) fmouse_test$(EXEEXT) \
+@CPPUNIT_TEST_TRUE@	fkeyboard_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	foptimove_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	foptiattr_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	fstring_test$(EXEEXT) fpoint_test$(EXEEXT) \
@@ -111,19 +113,25 @@ CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 @CPPUNIT_TEST_TRUE@am__EXEEXT_1 = fobject_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	fmouse_test$(EXEEXT) \
+@CPPUNIT_TEST_TRUE@	fkeyboard_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	foptimove_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	foptiattr_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	fstring_test$(EXEEXT) fpoint_test$(EXEEXT) \
 @CPPUNIT_TEST_TRUE@	frect_test$(EXEEXT)
 PROGRAMS = $(noinst_PROGRAMS)
-am__fmouse_test_SOURCES_DIST = fmouse-test.cpp
-@CPPUNIT_TEST_TRUE@am_fmouse_test_OBJECTS = fmouse-test.$(OBJEXT)
-fmouse_test_OBJECTS = $(am_fmouse_test_OBJECTS)
-fmouse_test_LDADD = $(LDADD)
+am__fkeyboard_test_SOURCES_DIST = fkeyboard-test.cpp
+@CPPUNIT_TEST_TRUE@am_fkeyboard_test_OBJECTS =  \
+@CPPUNIT_TEST_TRUE@	fkeyboard-test.$(OBJEXT)
+fkeyboard_test_OBJECTS = $(am_fkeyboard_test_OBJECTS)
+fkeyboard_test_LDADD = $(LDADD)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
+am__fmouse_test_SOURCES_DIST = fmouse-test.cpp
+@CPPUNIT_TEST_TRUE@am_fmouse_test_OBJECTS = fmouse-test.$(OBJEXT)
+fmouse_test_OBJECTS = $(am_fmouse_test_OBJECTS)
+fmouse_test_LDADD = $(LDADD)
 am__fobject_test_SOURCES_DIST = fobject-test.cpp
 @CPPUNIT_TEST_TRUE@am_fobject_test_OBJECTS = fobject-test.$(OBJEXT)
 fobject_test_OBJECTS = $(am_fobject_test_OBJECTS)
@@ -184,11 +192,12 @@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
 am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
 am__v_CXXLD_1 = 
-SOURCES = $(fmouse_test_SOURCES) $(fobject_test_SOURCES) \
-	$(foptiattr_test_SOURCES) $(foptimove_test_SOURCES) \
-	$(fpoint_test_SOURCES) $(frect_test_SOURCES) \
-	$(fstring_test_SOURCES)
-DIST_SOURCES = $(am__fmouse_test_SOURCES_DIST) \
+SOURCES = $(fkeyboard_test_SOURCES) $(fmouse_test_SOURCES) \
+	$(fobject_test_SOURCES) $(foptiattr_test_SOURCES) \
+	$(foptimove_test_SOURCES) $(fpoint_test_SOURCES) \
+	$(frect_test_SOURCES) $(fstring_test_SOURCES)
+DIST_SOURCES = $(am__fkeyboard_test_SOURCES_DIST) \
+	$(am__fmouse_test_SOURCES_DIST) \
 	$(am__fobject_test_SOURCES_DIST) \
 	$(am__foptiattr_test_SOURCES_DIST) \
 	$(am__foptimove_test_SOURCES_DIST) \
@@ -553,6 +562,7 @@ top_srcdir = @top_srcdir@
 @CPPUNIT_TEST_TRUE@AM_CPPFLAGS = -I$(top_srcdir)/include -Wall -Werror
 @CPPUNIT_TEST_TRUE@fobject_test_SOURCES = fobject-test.cpp
 @CPPUNIT_TEST_TRUE@fmouse_test_SOURCES = fmouse-test.cpp
+@CPPUNIT_TEST_TRUE@fkeyboard_test_SOURCES = fkeyboard-test.cpp
 @CPPUNIT_TEST_TRUE@foptimove_test_SOURCES = foptimove-test.cpp
 @CPPUNIT_TEST_TRUE@foptiattr_test_SOURCES = foptiattr-test.cpp
 @CPPUNIT_TEST_TRUE@fstring_test_SOURCES = fstring-test.cpp
@@ -611,6 +621,10 @@ clean-noinstPROGRAMS:
 	echo " rm -f" $$list; \
 	rm -f $$list
 
+fkeyboard_test$(EXEEXT): $(fkeyboard_test_OBJECTS) $(fkeyboard_test_DEPENDENCIES) $(EXTRA_fkeyboard_test_DEPENDENCIES) 
+	@rm -f fkeyboard_test$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(fkeyboard_test_OBJECTS) $(fkeyboard_test_LDADD) $(LIBS)
+
 fmouse_test$(EXEEXT): $(fmouse_test_OBJECTS) $(fmouse_test_DEPENDENCIES) $(EXTRA_fmouse_test_DEPENDENCIES) 
 	@rm -f fmouse_test$(EXEEXT)
 	$(AM_V_CXXLD)$(CXXLINK) $(fmouse_test_OBJECTS) $(fmouse_test_LDADD) $(LIBS)
@@ -645,6 +659,7 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fkeyboard-test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmouse-test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fobject-test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/foptiattr-test.Po@am__quote@
@@ -887,6 +902,13 @@ fmouse_test.log: fmouse_test$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+fkeyboard_test.log: fkeyboard_test$(EXEEXT)
+	@p='fkeyboard_test$(EXEEXT)'; \
+	b='fkeyboard_test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 foptimove_test.log: foptimove_test$(EXEEXT)
 	@p='foptimove_test$(EXEEXT)'; \
 	b='foptimove_test'; \
diff --git a/src/test/fkeyboard-test.cpp b/src/test/fkeyboard-test.cpp
new file mode 100644
index 00000000..67437091
--- /dev/null
+++ b/src/test/fkeyboard-test.cpp
@@ -0,0 +1,455 @@
+/***********************************************************************
+* fkeyboard-test.cpp - FKeyboard unit tests                            *
+*                                                                      *
+* This file is part of the Final Cut widget toolkit                    *
+*                                                                      *
+* Copyright 2018 Markus Gans                                           *
+*                                                                      *
+* The Final Cut is free software; you can redistribute it and/or       *
+* modify it under the terms of the GNU Lesser General Public License   *
+* as published by the Free Software Foundation; either version 3 of    *
+* the License, or (at your option) any later version.                  *
+*                                                                      *
+* The Final Cut is distributed in the hope that it will be useful,     *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of       *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
+* GNU Lesser General Public License for more details.                  *
+*                                                                      *
+* You should have received a copy of the GNU Lesser General Public     *
+* License along with this program.  If not, see                        *
+* .                                      *
+***********************************************************************/
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+namespace test
+{
+
+#pragma pack(push)
+#pragma pack(1)
+typedef struct
+{
+  int   num;
+  char* string;
+  char  tname[4];
+}
+fkeymap;
+#pragma pack(pop)
+
+fkeymap Fkey[] =
+{
+  { fc::Fkey_backspace, C_STR("\177")     , "kb" },  // backspace key
+  { fc::Fkey_catab    , 0                 , "ka" },  // clear-all-tabs key
+  { fc::Fkey_clear    , 0                 , "kC" },  // clear-screen or erase key
+  { fc::Fkey_ctab     , C_STR(CSI "3~")   , "kt" },  // clear-tab key
+  { fc::Fkey_dc       , 0                 , "kD" },  // delete-character key
+  { fc::Fkey_dl       , 0                 , "kL" },  // delete-line key
+  { fc::Fkey_down     , C_STR(ESC "OB")   , "kd" },  // down-arrow key
+  { fc::Fkey_down     , C_STR(CSI "B")    , "kdx"},  // down-arrow key
+  { fc::Fkey_eic      , 0                 , "kM" },  // sent by rmir or smir in insert mode
+  { fc::Fkey_eol      , 0                 , "kE" },  // clear-to-end-of-line key
+  { fc::Fkey_eos      , 0                 , "kS" },  // clear-to-end-of-screen key
+  { fc::Fkey_f0       , 0                 , "k0" },  // F0 function key
+  { fc::Fkey_f1       , C_STR(ESC "OP")   , "k1" },  // F1 function key
+  { fc::Fkey_f1       , C_STR(CSI "11~")  , "k1x"},  // F1 function key
+  { fc::Fkey_f1       , C_STR(ESC "OP")   , "k1X"},  // F1 function key
+  { fc::Fkey_f2       , C_STR(ESC "OQ")   , "k2" },  // F2 function key
+  { fc::Fkey_f2       , C_STR(CSI "12~")  , "k2x"},  // F2 function key
+  { fc::Fkey_f2       , C_STR(ESC "OQ")   , "k2X"},  // F2 function key
+  { fc::Fkey_f3       , C_STR(ESC "OR")   , "k3" },  // F3 function key
+  { fc::Fkey_f3       , C_STR(CSI "13~")  , "k3x"},  // F3 function key
+  { fc::Fkey_f3       , C_STR(ESC "OR")   , "k3X"},  // F3 function key
+  { fc::Fkey_f4       , C_STR(ESC "OS")   , "k4" },  // F4 function key
+  { fc::Fkey_f4       , C_STR(CSI "14~")  , "k4x"},  // F4 function key
+  { fc::Fkey_f4       , C_STR(ESC "OS")   , "k4X"},  // F4 function key
+  { fc::Fkey_f5       , C_STR(CSI "15~")  , "k5" },  // F5 function key
+  { fc::Fkey_f6       , C_STR(CSI "17~")  , "k6" },  // F6 function key
+  { fc::Fkey_f7       , C_STR(CSI "18~")  , "k7" },  // F7 function key
+  { fc::Fkey_f8       , C_STR(CSI "19~")  , "k8" },  // F8 fucntion key
+  { fc::Fkey_f9       , C_STR(CSI "20~")  , "k9" },  // F9 function key
+  { fc::Fkey_f10      , C_STR(CSI "21~")  , "k;" },  // F10 function key
+  { fc::Fkey_home     , C_STR(ESC "OH")   , "kh" },  // home key
+  { fc::Fkey_home     , C_STR(CSI "7~")   , "khx"},  // home key
+  { fc::Fkey_ic       , C_STR(CSI "2~")   , "kI" },  // insert-character key
+  { fc::Fkey_il       , 0                 , "kA" },  // insert-line key
+  { fc::Fkey_left     , C_STR(ESC "OD")   , "kl" },  // left-arrow key
+  { fc::Fkey_left     , C_STR(CSI "D")    , "klx"},  // left-arrow key
+  { fc::Fkey_ll       , 0                 , "kH" },  // last-line key
+  { fc::Fkey_npage    , C_STR(CSI "6~")   , "kN" },  // next-page key
+  { fc::Fkey_ppage    , C_STR(CSI "5~")   , "kP" },  // prev-page key
+  { fc::Fkey_right    , C_STR(ESC "OC")   , "kr" },  // right-arrow key
+  { fc::Fkey_right    , C_STR(CSI "C")    , "krx"},  // right-arrow key
+  { fc::Fkey_sf       , C_STR(CSI "1;2B") , "kF" },  // scroll-forward key
+  { fc::Fkey_sr       , C_STR(CSI "1;2A") , "kR" },  // scroll-backward key
+  { fc::Fkey_stab     , 0                 , "kT" },  // set-tab key
+  { fc::Fkey_up       , C_STR(ESC "OA")   , "ku" },  // up-arrow key
+  { fc::Fkey_up       , C_STR(CSI "A")    , "kux"},  // up-arrow key
+  { fc::Fkey_a1       , 0                 , "K1" },  // upper left of keypad
+  { fc::Fkey_a3       , 0                 , "K3" },  // upper right of keypad
+  { fc::Fkey_b2       , C_STR(CSI "E")    , "K2" },  // center of keypad
+  { fc::Fkey_c1       , 0                 , "K4" },  // lower left of keypad
+  { fc::Fkey_c3       , 0                 , "K5" },  // lower right of keypad
+  { fc::Fkey_btab     , C_STR(CSI "Z")    , "kB" },  // back-tab key
+  { fc::Fkey_beg      , 0                 , "@1" },  // begin key
+  { fc::Fkey_cancel   , 0                 , "@2" },  // cancel key
+  { fc::Fkey_close    , 0                 , "@3" },  // close key
+  { fc::Fkey_command  , 0                 , "@4" },  // command key
+  { fc::Fkey_copy     , 0                 , "@5" },  // copy key
+  { fc::Fkey_create   , 0                 , "@6" },  // create key
+  { fc::Fkey_end      , C_STR(ESC "OF")   , "@7" },  // end key
+  { fc::Fkey_end      , C_STR(CSI "8~")   , "@7x"},  // end key
+  { fc::Fkey_end      , C_STR(CSI "K")    , "@7X"},  // end key
+  { fc::Fkey_enter    , 0                 , "@8" },  // enter/send key
+  { fc::Fkey_exit     , 0                 , "@9" },  // exit key
+  { fc::Fkey_find     , C_STR(CSI "1~")   , "@0" },  // find key
+  { fc::Fkey_help     , 0                 , "%1" },  // help key
+  { fc::Fkey_mark     , 0                 , "%2" },  // mark key
+  { fc::Fkey_message  , 0                 , "%3" },  // message key
+  { fc::Fkey_move     , 0                 , "%4" },  // move key
+  { fc::Fkey_next     , 0                 , "%5" },  // next key
+  { fc::Fkey_open     , 0                 , "%6" },  // open key
+  { fc::Fkey_options  , 0                 , "%7" },  // options key
+  { fc::Fkey_previous , 0                 , "%8" },  // previous key
+  { fc::Fkey_print    , 0                 , "%9" },  // print key
+  { fc::Fkey_redo     , 0                 , "%0" },  // redo key
+  { fc::Fkey_reference, 0                 , "&1" },  // reference key
+  { fc::Fkey_refresh  , 0                 , "&2" },  // refresh key
+  { fc::Fkey_replace  , 0                 , "&3" },  // replace key
+  { fc::Fkey_restart  , 0                 , "&4" },  // restart key
+  { fc::Fkey_resume   , 0                 , "&5" },  // resume key
+  { fc::Fkey_save     , 0                 , "&6" },  // save key
+  { fc::Fkey_suspend  , 0                 , "&7" },  // suspend key
+  { fc::Fkey_undo     , 0                 , "&8" },  // undo key
+  { fc::Fkey_sbeg     , 0                 , "&9" },  // shifted key
+  { fc::Fkey_scancel  , 0                 , "&0" },  // shifted key
+  { fc::Fkey_scommand , 0                 , "*1" },  // shifted key
+  { fc::Fkey_scopy    , 0                 , "*2" },  // shifted key
+  { fc::Fkey_screate  , 0                 , "*3" },  // shifted key
+  { fc::Fkey_sdc      , C_STR(CSI "3;2~") , "*4" },  // shifted key
+  { fc::Fkey_sdl      , 0                 , "*5" },  // shifted key
+  { fc::Fkey_select   , C_STR(CSI "4~")   , "*6" },  // select key
+  { fc::Fkey_send     , C_STR(CSI "1;2F") , "*7" },  // shifted key
+  { fc::Fkey_seol     , 0                 , "*8" },  // shifted key
+  { fc::Fkey_sexit    , 0                 , "*9" },  // shifted key
+  { fc::Fkey_sfind    , 0                 , "*0" },  // shifted key
+  { fc::Fkey_shelp    , 0                 , "#1" },  // shifted key
+  { fc::Fkey_shome    , C_STR(CSI "1;2H") , "#2" },  // shifted key
+  { fc::Fkey_sic      , C_STR(CSI "2;2~") , "#3" },  // shifted key
+  { fc::Fkey_sleft    , C_STR(CSI "1;2D") , "#4" },  // shifted key
+  { fc::Fkey_smessage , 0                 , "%a" },  // shifted key
+  { fc::Fkey_smove    , 0                 , "%b" },  // shifted key
+  { fc::Fkey_snext    , C_STR(CSI "6;2~") , "%c" },  // shifted key
+  { fc::Fkey_soptions , 0                 , "%d" },  // shifted key
+  { fc::Fkey_sprevious, C_STR(CSI "5;2~") , "%e" },  // shifted key
+  { fc::Fkey_sprint   , 0                 , "%f" },  // shifted key
+  { fc::Fkey_sredo    , 0                 , "%g" },  // shifted key
+  { fc::Fkey_sreplace , 0                 , "%h" },  // shifted key
+  { fc::Fkey_sright   , C_STR(CSI "1;2C") , "%i" },  // shifted key
+  { fc::Fkey_srsume   , 0                 , "%j" },  // shifted key
+  { fc::Fkey_ssave    , 0                 , "!1" },  // shifted key
+  { fc::Fkey_ssuspend , 0                 , "!2" },  // shifted key
+  { fc::Fkey_sundo    , 0                 , "!3" },  // shifted key
+  { fc::Fkey_f11      , C_STR(CSI "23~")  , "F1" },  // F11 function key
+  { fc::Fkey_f12      , C_STR(CSI "24~")  , "F2" },  // F12 function key
+  { fc::Fkey_f13      , C_STR(ESC "O1;2P"), "F3" },  // F13 function key
+  { fc::Fkey_f14      , C_STR(ESC "O1;2Q"), "F4" },  // F14 function key
+  { fc::Fkey_f15      , C_STR(ESC "O1;2R"), "F5" },  // F15 function key
+  { fc::Fkey_f16      , C_STR(ESC "O1;2S"), "F6" },  // F16 function key
+  { fc::Fkey_f17      , C_STR(CSI "15;2~"), "F7" },  // F17 function key
+  { fc::Fkey_f18      , C_STR(CSI "17;2~"), "F8" },  // F18 function key
+  { fc::Fkey_f19      , C_STR(CSI "18;2~"), "F9" },  // F19 function key
+  { fc::Fkey_f20      , C_STR(CSI "19;2~"), "FA" },  // F20 function key
+  { fc::Fkey_f21      , C_STR(CSI "20;2~"), "FB" },  // F21 function key
+  { fc::Fkey_f22      , C_STR(CSI "21;2~"), "FC" },  // F22 function key
+  { fc::Fkey_f23      , C_STR(CSI "23;2~"), "FD" },  // F23 function key
+  { fc::Fkey_f24      , C_STR(CSI "24;2~"), "FE" },  // F24 function key
+  { fc::Fkey_f25      , C_STR(ESC "O1;5P"), "FF" },  // F25 function key
+  { fc::Fkey_f26      , C_STR(ESC "O1;5Q"), "FG" },  // F26 function key
+  { fc::Fkey_f27      , C_STR(ESC "O1;5R"), "FH" },  // F27 function key
+  { fc::Fkey_f28      , C_STR(ESC "O1;5S"), "FI" },  // F28 function key
+  { fc::Fkey_f29      , C_STR(CSI "15;5~"), "FJ" },  // F29 function key
+  { fc::Fkey_f30      , C_STR(CSI "17;5~"), "FK" },  // F30 function key
+  { fc::Fkey_f31      , C_STR(CSI "18;5~"), "FL" },  // F31 function key
+  { fc::Fkey_f32      , C_STR(CSI "19;5~"), "FM" },  // F32 function key
+  { fc::Fkey_f33      , C_STR(CSI "20;5~"), "FN" },  // F33 function key
+  { fc::Fkey_f34      , C_STR(CSI "21;5~"), "FO" },  // F34 function key
+  { fc::Fkey_f35      , C_STR(CSI "23;5~"), "FP" },  // F35 function key
+  { fc::Fkey_f36      , C_STR(CSI "24;5~"), "FQ" },  // F36 function key
+  { fc::Fkey_f37      , C_STR(ESC "O1;6P"), "FR" },  // F37 function key
+  { fc::Fkey_f38      , C_STR(ESC "O1;6Q"), "FS" },  // F38 function key
+  { fc::Fkey_f39      , C_STR(ESC "O1;6R"), "FT" },  // F39 function key
+  { fc::Fkey_f40      , C_STR(ESC "O1;6S"), "FU" },  // F40 function key
+  { fc::Fkey_f41      , C_STR(CSI "15;6~"), "FV" },  // F41 function key
+  { fc::Fkey_f42      , C_STR(CSI "17;6~"), "FW" },  // F42 function key
+  { fc::Fkey_f43      , C_STR(CSI "18;6~"), "FX" },  // F43 function key
+  { fc::Fkey_f44      , C_STR(CSI "19;6~"), "FY" },  // F44 function key
+  { fc::Fkey_f45      , C_STR(CSI "20;6~"), "FZ" },  // F45 function key
+  { fc::Fkey_f46      , C_STR(CSI "21;6~"), "Fa" },  // F46 function key
+  { fc::Fkey_f47      , C_STR(CSI "23;6~"), "Fb" },  // F47 function key
+  { fc::Fkey_f48      , C_STR(CSI "24;6~"), "Fc" },  // F48 function key
+  { fc::Fkey_f49      , C_STR(ESC "O1;3P"), "Fd" },  // F49 function key
+  { fc::Fkey_f50      , C_STR(ESC "O1;3Q"), "Fe" },  // F50 function key
+  { fc::Fkey_f51      , C_STR(ESC "O1;3R"), "Ff" },  // F51 function key
+  { fc::Fkey_f52      , C_STR(ESC "O1;3S"), "Fg" },  // F52 function key
+  { fc::Fkey_f53      , C_STR(CSI "15;3~"), "Fh" },  // F53 function key
+  { fc::Fkey_f54      , C_STR(CSI "17;3~"), "Fi" },  // F54 function key
+  { fc::Fkey_f55      , C_STR(CSI "18;3~"), "Fj" },  // F55 function key
+  { fc::Fkey_f56      , C_STR(CSI "19;3~"), "Fk" },  // F56 function key
+  { fc::Fkey_f57      , C_STR(CSI "20;3~"), "Fl" },  // F57 function key
+  { fc::Fkey_f58      , C_STR(CSI "21;3~"), "Fm" },  // F58 function key
+  { fc::Fkey_f59      , C_STR(CSI "23;3~"), "Fn" },  // F59 function key
+  { fc::Fkey_f60      , C_STR(CSI "24;3~"), "Fo" },  // F60 function key
+  { fc::Fkey_f61      , C_STR(ESC "O1;4P"), "Fp" },  // F61 function key
+  { fc::Fkey_f62      , C_STR(ESC "O1;4Q"), "Fq" },  // F62 function key
+  { fc::Fkey_f63      , C_STR(ESC "O1;4R"), "Fr" },  // F63 function key
+  { 0                 , 0                 , "\0" }
+};
+
+}  // namespace test
+
+
+//----------------------------------------------------------------------
+// class FKeyboardTest
+//----------------------------------------------------------------------
+
+#pragma pack(push)
+#pragma pack(1)
+
+class FKeyboardTest : public CPPUNIT_NS::TestFixture
+{
+  public:
+    FKeyboardTest();
+
+  protected:
+    void classNameTest();
+    void noArgumentTest();
+    void inputTest();
+
+  private:
+    // Adds code needed to register the test suite
+    CPPUNIT_TEST_SUITE (FKeyboardTest);
+
+    // Add a methods to the test suite
+    CPPUNIT_TEST (classNameTest);
+    CPPUNIT_TEST (noArgumentTest);
+    CPPUNIT_TEST (inputTest);
+
+    // End of test suite definition
+    CPPUNIT_TEST_SUITE_END();
+    void input (std::string);
+    void processInput();
+    void clear();
+    void keyPressed();
+    void keyReleased();
+    void escapeKeyPressed();
+
+    // Data Members
+    int key_pressed;
+    int key_released;
+    FKeyboard* keyboard;
+    //FTerm t;
+};
+#pragma pack(pop)
+
+FKeyboardTest::FKeyboardTest()
+  : key_pressed(0)
+  , key_released(0)
+  , keyboard(0)
+{
+  keyboard = new FKeyboard();
+  FApplication* object = reinterpret_cast(this);
+  void (FApplication::*method1)()
+      = reinterpret_cast(&FKeyboardTest::keyPressed);
+  void (FApplication::*method2)()
+      = reinterpret_cast(&FKeyboardTest::keyReleased);
+  void (FApplication::*method3)()
+      = reinterpret_cast(&FKeyboardTest::escapeKeyPressed);
+  FKeyboardCommand key_cmd1 (object, method1);
+  FKeyboardCommand key_cmd2 (object, method2);
+  FKeyboardCommand key_cmd3 (object, method3);
+  keyboard->setPressCommand (key_cmd1);
+  keyboard->setReleaseCommand (key_cmd2);
+  keyboard->setEscPressedCommand (key_cmd3);
+  keyboard->setKeypressTimeout (100000);  // 100 ms
+  keyboard->enableUTF8();
+  keyboard->enableMouseSequences();
+  keyboard->setTermcapMap (reinterpret_cast(test::Fkey));
+}
+
+//----------------------------------------------------------------------
+void FKeyboardTest::classNameTest()
+{
+  FKeyboard k;
+  const char* const classname = k.getClassName();
+  CPPUNIT_ASSERT ( std::strcmp(classname, "FKeyboard") == 0 );
+}
+
+//----------------------------------------------------------------------
+void FKeyboardTest::noArgumentTest()
+{
+  CPPUNIT_ASSERT ( keyboard->getKey() == 0 );
+  char* buffer = keyboard->getKeyBuffer();
+  int size = keyboard->getKeyBufferSize();
+
+  CPPUNIT_ASSERT ( size == 512 );
+  CPPUNIT_ASSERT ( buffer[0] == 0 );
+  int sum = 0;
+
+  for (int i = 0; i < size; i++)
+    sum += int(buffer[i]);
+
+  CPPUNIT_ASSERT ( sum == 0 );
+
+  timeval* time = keyboard->getKeyPressedTime();
+  CPPUNIT_ASSERT ( time->tv_sec == 0);
+  CPPUNIT_ASSERT ( time->tv_usec == 0);
+
+  CPPUNIT_ASSERT ( ! keyboard->isInputDataPending() );
+  CPPUNIT_ASSERT ( ! keyboard->unprocessedInput() );
+  CPPUNIT_ASSERT ( ! keyboard->isKeyPressed() );
+
+  keyboard->clearKeyBufferOnTimeout();
+
+  if ( keyboard->isKeyPressed() )
+    keyboard->fetchKeyCode();
+
+  // special case: Esc key
+  keyboard->escapeKeyHandling();
+
+  CPPUNIT_ASSERT ( keyboard->getKey() == 0 );
+}
+
+//----------------------------------------------------------------------
+void FKeyboardTest::inputTest()
+{
+  std::cout << std::endl;
+  input("\033[M Z2");
+  processInput();
+  std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl;
+  CPPUNIT_ASSERT ( key_pressed == fc::Fkey_mouse );
+  clear();
+
+  input("\033[<0;11;7M");
+  processInput();
+  std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl;
+  CPPUNIT_ASSERT ( key_pressed == fc::Fkey_extended_mouse );
+  clear();
+
+  input("\033[32;11;7M");
+  processInput();
+  std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl;
+  CPPUNIT_ASSERT ( key_pressed == fc::Fkey_urxvt_mouse );
+  clear();
+
+  input("\033O[");
+  processInput();
+  std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl;
+  CPPUNIT_ASSERT ( key_pressed == fc::Fkey_escape_mintty );
+  clear();
+
+  input("\033");
+  processInput();
+  usleep(100000);
+  keyboard->escapeKeyHandling();
+  std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl;
+  CPPUNIT_ASSERT ( key_pressed == fc::Fkey_escape );
+  clear();
+
+  input("\033[3~");
+  processInput();
+  std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl;
+  CPPUNIT_ASSERT ( key_pressed == fc::Fkey_ctab );
+  clear();
+
+  input("\033OB");
+  processInput();
+  std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl;
+  CPPUNIT_ASSERT ( key_pressed == fc::Fkey_down );
+  clear();
+
+  input("\033[B");
+  processInput();
+  std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl;
+  CPPUNIT_ASSERT ( key_pressed == fc::Fkey_down );
+  clear();
+
+  input("aA");
+  processInput();
+  std::cout << " - Key: " << keyboard->getKeyName(key_pressed) << std::endl;
+  CPPUNIT_ASSERT ( key_pressed == 'A' );
+  CPPUNIT_ASSERT ( key_released == 'A' );
+  clear();
+
+}
+
+//----------------------------------------------------------------------
+void FKeyboardTest::input (std::string s)
+{
+  // Simulates keystrokes
+
+  const char EOT = 0x04;  // End of Transmission
+
+  std::string::const_iterator iter;
+  iter = s.begin();
+
+  while ( iter != s.end() )
+  {
+    char c = *iter;
+    ioctl (FTermios::getStdIn(), TIOCSTI, &c);
+    ++iter;
+  }
+
+  ioctl (FTermios::getStdIn(), TIOCSTI, &EOT);
+}
+
+//----------------------------------------------------------------------
+void FKeyboardTest::processInput()
+{
+  keyboard->clearKeyBufferOnTimeout();
+
+  if ( keyboard->isKeyPressed() )
+    keyboard->fetchKeyCode();
+
+  // special case: Esc key
+  keyboard->escapeKeyHandling();
+}
+
+//----------------------------------------------------------------------
+void FKeyboardTest::clear()
+{
+  keyboard->clearKeyBuffer();
+  key_pressed = key_released = 0;
+}
+
+//----------------------------------------------------------------------
+void FKeyboardTest::keyPressed()
+{
+  key_pressed = keyboard->getKey();
+}
+
+//----------------------------------------------------------------------
+void FKeyboardTest::keyReleased()
+{
+  key_released = keyboard->getKey();
+}
+
+//----------------------------------------------------------------------
+void FKeyboardTest::escapeKeyPressed()
+{
+  key_pressed = fc::Fkey_escape;
+  key_released = fc::Fkey_escape;
+}
+
+// Put the test suite in the registry
+CPPUNIT_TEST_SUITE_REGISTRATION (FKeyboardTest);
+
+// The general unit test main part
+#include