diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
index babb097..597b15d 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.c
@@ -81,6 +81,12 @@ TERMINAL_DEV  mTerminalDevTemplate = {
   NULL, // TwoSecondTimeOut
   INPUT_STATE_DEFAULT,
   RESET_STATE_DEFAULT,
+  {
+      0,
+      0,
+      0
+  },
+  0,
   FALSE,
   {   // SimpleTextInputEx
     TerminalConInResetEx,
diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
index 03542a4..269d2ae 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/Terminal.h
@@ -99,6 +99,8 @@ typedef struct {
   EFI_EVENT                           TwoSecondTimeOut;
   UINT32                              InputState;
   UINT32                              ResetState;
+  UINT16                              TtyEscapeStr[3];
+  INTN                                TtyEscapeIndex;
 
   //
   // Esc could not be output to the screen by user,
@@ -118,6 +120,7 @@ typedef struct {
 #define INPUT_STATE_LEFTOPENBRACKET       0x04
 #define INPUT_STATE_O                     0x08
 #define INPUT_STATE_2                     0x10
+#define INPUT_STATE_LEFTOPENBRACKET_2     0x20
 
 #define RESET_STATE_DEFAULT               0x00
 #define RESET_STATE_ESC_R                 0x01
diff --git a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
index 227df85..fbaf33b 100644
--- a/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
+++ b/MdeModulePkg/Universal/Console/TerminalDxe/TerminalConIn.c
@@ -1223,7 +1223,8 @@ UnicodeToEfiKey (
         continue;
       }
 
-      if (UnicodeChar == 'O' && TerminalDevice->TerminalType == VT100TYPE) {
+      if (UnicodeChar == 'O' && (TerminalDevice->TerminalType == VT100TYPE ||
+                                 TerminalDevice->TerminalType == TTYTERMTYPE)) {
         TerminalDevice->InputState |= INPUT_STATE_O;
         TerminalDevice->ResetState = RESET_STATE_DEFAULT;
         continue;
@@ -1371,6 +1372,22 @@ UnicodeToEfiKey (
         default :
           break;
         }
+      } else if (TerminalDevice->TerminalType == TTYTERMTYPE) {
+        /* Also accept VT100 escape codes for F1-F4 for TTY term */
+        switch (UnicodeChar) {
+        case 'P':
+          Key.ScanCode = SCAN_F1;
+          break;
+        case 'Q':
+          Key.ScanCode = SCAN_F2;
+          break;
+        case 'R':
+          Key.ScanCode = SCAN_F3;
+          break;
+        case 'S':
+          Key.ScanCode = SCAN_F4;
+          break;
+        }
       }
 
       if (Key.ScanCode != SCAN_NULL) {
@@ -1514,6 +1531,21 @@ UnicodeToEfiKey (
         }
       }
 
+      /*
+       * The VT220 escape codes that the TTY terminal accepts all have
+       * numeric codes, and there are no ambiguous prefixes shared with
+       * other terminal types.
+       */
+      if (TerminalDevice->TerminalType == TTYTERMTYPE &&
+          Key.ScanCode == SCAN_NULL &&
+          UnicodeChar >= '0' &&
+          UnicodeChar <= '9') {
+        TerminalDevice->TtyEscapeStr[0] = UnicodeChar;
+        TerminalDevice->TtyEscapeIndex = 1;
+        TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET_2;
+        continue;
+      }
+
       if (Key.ScanCode != SCAN_NULL) {
         Key.UnicodeChar = 0;
         EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
@@ -1527,6 +1559,65 @@ UnicodeToEfiKey (
       break;
 
 
+    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_LEFTOPENBRACKET_2:
+      /*
+       * Here we handle the VT220 escape codes that we accept.  This
+       * state is only used by the TTY terminal type.
+       */
+      Key.ScanCode = SCAN_NULL;
+      if (TerminalDevice->TerminalType == TTYTERMTYPE) {
+
+        if (UnicodeChar == '~' && TerminalDevice->TtyEscapeIndex <= 2) {
+          UINTN EscCode;
+          TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex] = 0; /* Terminate string */
+          EscCode = StrDecimalToUintn(TerminalDevice->TtyEscapeStr);
+          switch (EscCode) {
+          case 3:
+              Key.ScanCode = SCAN_DELETE;
+              break;
+          case 11:
+          case 12:
+          case 13:
+          case 14:
+          case 15:
+            Key.ScanCode = SCAN_F1 + EscCode - 11;
+            break;
+          case 17:
+          case 18:
+          case 19:
+          case 20:
+          case 21:
+            Key.ScanCode = SCAN_F6 + EscCode - 17;
+            break;
+          case 23:
+          case 24:
+            Key.ScanCode = SCAN_F11 + EscCode - 23;
+            break;
+          default:
+            break;
+          }
+        } else if (TerminalDevice->TtyEscapeIndex == 1){
+          /* 2 character escape code   */
+          TerminalDevice->TtyEscapeStr[TerminalDevice->TtyEscapeIndex++] = UnicodeChar;
+          continue;
+        }
+        else {
+          DEBUG ((EFI_D_ERROR, "Unexpected state in escape2\n"));
+        }
+      }
+      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
+
+      if (Key.ScanCode != SCAN_NULL) {
+        Key.UnicodeChar = 0;
+        EfiKeyFiFoInsertOneKey (TerminalDevice, &Key);
+        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
+        UnicodeToEfiKeyFlushState (TerminalDevice);
+        continue;
+      }
+
+      UnicodeToEfiKeyFlushState (TerminalDevice);
+      break;
+
     default:
       //
       // Invalid state. This should never happen.
