Support for Xterm ctrl/alt/shift function keys
authorKevin Lamonte <kevin.lamonte@gmail.com>
Tue, 31 Jan 2017 17:46:23 +0000 (12:46 -0500)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Tue, 31 Jan 2017 17:46:23 +0000 (12:46 -0500)
src/jexer/TKeypress.java
src/jexer/TWindow.java
src/jexer/io/ECMA48Terminal.java
src/jexer/tterminal/ECMA48.java

index 5d1eabc9889adc057fdbda821e91de5b52c09d5e..5e551d8c18f4397a33bb0dd10ebe1544c06ff728 100644 (file)
@@ -296,6 +296,23 @@ public final class TKeypress {
                 && (shift == that.shift));
     }
 
+    /**
+     * Comparison check, omitting the ctrl/alt/shift flags.
+     *
+     * @param rhs another TKeypress instance
+     * @return true if all fields (except for ctrl/alt/shift) are equal
+     */
+    public boolean equalsWithoutModifiers(final Object rhs) {
+        if (!(rhs instanceof TKeypress)) {
+            return false;
+        }
+
+        TKeypress that = (TKeypress) rhs;
+        return ((isFunctionKey == that.isFunctionKey)
+                && (keyCode == that.keyCode)
+                && (ch == that.ch));
+    }
+
     /**
      * Hashcode uses all fields in equals().
      *
index 10f4e59d5df5d946a5d7032475a590552bbdf7ac..26bd8c453a1922bfd8f79b47c61b35f1470ae429 100644 (file)
@@ -736,8 +736,8 @@ public class TWindow extends TWidget {
 
         if (inKeyboardResize) {
 
-            // ESC - Exit size/move
-            if (keypress.equals(kbEsc)) {
+            // ESC or ENTER - Exit size/move
+            if (keypress.equals(kbEsc) || keypress.equals(kbEnter)) {
                 inKeyboardResize = false;
             }
 
index 2af3a3e3d53ae1bee6283b1e4c5f020179b8c426..069c143f2d32e9a8c6f86dc474ac2149df6f2244 100644 (file)
@@ -104,7 +104,6 @@ public final class ECMA48Terminal implements Runnable {
         ESCAPE_INTERMEDIATE,
         CSI_ENTRY,
         CSI_PARAM,
-        // CSI_INTERMEDIATE,
         MOUSE,
         MOUSE_SGR,
     }
@@ -442,36 +441,16 @@ public final class ECMA48Terminal implements Runnable {
      */
     private TInputEvent csiFnKey() {
         int key = 0;
-        int modifier = 0;
         if (params.size() > 0) {
             key = Integer.parseInt(params.get(0));
         }
-        if (params.size() > 1) {
-            modifier = Integer.parseInt(params.get(1));
-        }
         boolean alt = false;
         boolean ctrl = false;
         boolean shift = false;
-
-        switch (modifier) {
-        case 0:
-            // No modifier
-            break;
-        case 2:
-            // Shift
-            shift = true;
-            break;
-        case 3:
-            // Alt
-            alt = true;
-            break;
-        case 5:
-            // Ctrl
-            ctrl = true;
-            break;
-        default:
-            // Unknown modifier, bail out
-            return null;
+        if (params.size() > 1) {
+            shift = csiIsShift(params.get(1));
+            alt = csiIsAlt(params.get(1));
+            ctrl = csiIsCtrl(params.get(1));
         }
 
         switch (key) {
@@ -777,6 +756,51 @@ public final class ECMA48Terminal implements Runnable {
         }
     }
 
+    /**
+     * Returns true if the CSI parameter for a keyboard command means that
+     * shift was down.
+     */
+    private boolean csiIsShift(final String x) {
+        if ((x.equals("2"))
+            || (x.equals("4"))
+            || (x.equals("6"))
+            || (x.equals("8"))
+        ) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the CSI parameter for a keyboard command means that
+     * alt was down.
+     */
+    private boolean csiIsAlt(final String x) {
+        if ((x.equals("3"))
+            || (x.equals("4"))
+            || (x.equals("7"))
+            || (x.equals("8"))
+        ) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the CSI parameter for a keyboard command means that
+     * ctrl was down.
+     */
+    private boolean csiIsCtrl(final String x) {
+        if ((x.equals("5"))
+            || (x.equals("6"))
+            || (x.equals("7"))
+            || (x.equals("8"))
+        ) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Parses the next character of input to see if an InputEvent is
      * fully here.
@@ -904,65 +928,21 @@ public final class ECMA48Terminal implements Runnable {
                 switch (ch) {
                 case 'A':
                     // Up
-                    if (params.size() > 1) {
-                        if (params.get(1).equals("2")) {
-                            shift = true;
-                        }
-                        if (params.get(1).equals("5")) {
-                            ctrl = true;
-                        }
-                        if (params.get(1).equals("3")) {
-                            alt = true;
-                        }
-                    }
                     events.add(new TKeypressEvent(kbUp, alt, ctrl, shift));
                     reset();
                     return;
                 case 'B':
                     // Down
-                    if (params.size() > 1) {
-                        if (params.get(1).equals("2")) {
-                            shift = true;
-                        }
-                        if (params.get(1).equals("5")) {
-                            ctrl = true;
-                        }
-                        if (params.get(1).equals("3")) {
-                            alt = true;
-                        }
-                    }
                     events.add(new TKeypressEvent(kbDown, alt, ctrl, shift));
                     reset();
                     return;
                 case 'C':
                     // Right
-                    if (params.size() > 1) {
-                        if (params.get(1).equals("2")) {
-                            shift = true;
-                        }
-                        if (params.get(1).equals("5")) {
-                            ctrl = true;
-                        }
-                        if (params.get(1).equals("3")) {
-                            alt = true;
-                        }
-                    }
                     events.add(new TKeypressEvent(kbRight, alt, ctrl, shift));
                     reset();
                     return;
                 case 'D':
                     // Left
-                    if (params.size() > 1) {
-                        if (params.get(1).equals("2")) {
-                            shift = true;
-                        }
-                        if (params.get(1).equals("5")) {
-                            ctrl = true;
-                        }
-                        if (params.get(1).equals("3")) {
-                            alt = true;
-                        }
-                    }
                     events.add(new TKeypressEvent(kbLeft, alt, ctrl, shift));
                     reset();
                     return;
@@ -1061,15 +1041,9 @@ public final class ECMA48Terminal implements Runnable {
                 case 'A':
                     // Up
                     if (params.size() > 1) {
-                        if (params.get(1).equals("2")) {
-                            shift = true;
-                        }
-                        if (params.get(1).equals("5")) {
-                            ctrl = true;
-                        }
-                        if (params.get(1).equals("3")) {
-                            alt = true;
-                        }
+                        shift = csiIsShift(params.get(1));
+                        alt = csiIsAlt(params.get(1));
+                        ctrl = csiIsCtrl(params.get(1));
                     }
                     events.add(new TKeypressEvent(kbUp, alt, ctrl, shift));
                     reset();
@@ -1077,15 +1051,9 @@ public final class ECMA48Terminal implements Runnable {
                 case 'B':
                     // Down
                     if (params.size() > 1) {
-                        if (params.get(1).equals("2")) {
-                            shift = true;
-                        }
-                        if (params.get(1).equals("5")) {
-                            ctrl = true;
-                        }
-                        if (params.get(1).equals("3")) {
-                            alt = true;
-                        }
+                        shift = csiIsShift(params.get(1));
+                        alt = csiIsAlt(params.get(1));
+                        ctrl = csiIsCtrl(params.get(1));
                     }
                     events.add(new TKeypressEvent(kbDown, alt, ctrl, shift));
                     reset();
@@ -1093,15 +1061,9 @@ public final class ECMA48Terminal implements Runnable {
                 case 'C':
                     // Right
                     if (params.size() > 1) {
-                        if (params.get(1).equals("2")) {
-                            shift = true;
-                        }
-                        if (params.get(1).equals("5")) {
-                            ctrl = true;
-                        }
-                        if (params.get(1).equals("3")) {
-                            alt = true;
-                        }
+                        shift = csiIsShift(params.get(1));
+                        alt = csiIsAlt(params.get(1));
+                        ctrl = csiIsCtrl(params.get(1));
                     }
                     events.add(new TKeypressEvent(kbRight, alt, ctrl, shift));
                     reset();
@@ -1109,19 +1071,33 @@ public final class ECMA48Terminal implements Runnable {
                 case 'D':
                     // Left
                     if (params.size() > 1) {
-                        if (params.get(1).equals("2")) {
-                            shift = true;
-                        }
-                        if (params.get(1).equals("5")) {
-                            ctrl = true;
-                        }
-                        if (params.get(1).equals("3")) {
-                            alt = true;
-                        }
+                        shift = csiIsShift(params.get(1));
+                        alt = csiIsAlt(params.get(1));
+                        ctrl = csiIsCtrl(params.get(1));
                     }
                     events.add(new TKeypressEvent(kbLeft, alt, ctrl, shift));
                     reset();
                     return;
+                case 'H':
+                    // Home
+                    if (params.size() > 1) {
+                        shift = csiIsShift(params.get(1));
+                        alt = csiIsAlt(params.get(1));
+                        ctrl = csiIsCtrl(params.get(1));
+                    }
+                    events.add(new TKeypressEvent(kbHome, alt, ctrl, shift));
+                    reset();
+                    return;
+                case 'F':
+                    // End
+                    if (params.size() > 1) {
+                        shift = csiIsShift(params.get(1));
+                        alt = csiIsAlt(params.get(1));
+                        ctrl = csiIsCtrl(params.get(1));
+                    }
+                    events.add(new TKeypressEvent(kbEnd, alt, ctrl, shift));
+                    reset();
+                    return;
                 default:
                     break;
                 }
@@ -1404,9 +1380,9 @@ public final class ECMA48Terminal implements Runnable {
      */
     private String mouse(final boolean on) {
         if (on) {
-            return "\033[?1003;1005;1006h\033[?1049h";
+            return "\033[?1002;1003;1005;1006h\033[?1049h";
         }
-        return "\033[?1003;1006;1005l\033[?1049l";
+        return "\033[?1002;1003;1006;1005l\033[?1049l";
     }
 
     /**
index f088f6a75b598afab9047f94cb60eec1afafce0e..97c9b41711624adef14e228d01b2049598b6b050 100644 (file)
@@ -1255,6 +1255,46 @@ public class ECMA48 implements Runnable {
         writeRemote(keypressToString(keypress));
     }
 
+    /**
+     * Build one of the complex xterm keystroke sequences, storing the result in
+     * xterm_keystroke_buffer.
+     *
+     * @param ss3 the prefix to use based on VT100 state.
+     * @param first the first character, usually a number.
+     * @param first the last character, one of the following: ~ A B C D F H
+     * @param ctrl whether or not ctrl is down
+     * @param alt whether or not alt is down
+     * @param shift whether or not shift is down
+     * @return the buffer with the full key sequence
+     */
+    private String xtermBuildKeySequence(final String ss3, final char first,
+        final char last, boolean ctrl, boolean alt, boolean shift) {
+
+        StringBuilder sb = new StringBuilder(ss3);
+        if ((last == '~') || (ctrl == true) || (alt == true)
+            || (shift == true)
+        ) {
+            sb.append(first);
+            if (       (ctrl == false) && (alt == false) && (shift == true)) {
+                sb.append(";2");
+            } else if ((ctrl == false) && (alt == true) && (shift == false)) {
+                sb.append(";3");
+            } else if ((ctrl == false) && (alt == true) && (shift == true)) {
+                sb.append(";4");
+            } else if ((ctrl == true) && (alt == false) && (shift == false)) {
+                sb.append(";5");
+            } else if ((ctrl == true) && (alt == false) && (shift == true)) {
+                sb.append(";6");
+            } else if ((ctrl == true) && (alt == true) && (shift == false)) {
+                sb.append(";7");
+            } else if ((ctrl == true) && (alt == true) && (shift == true)) {
+                sb.append(";8");
+            }
+        }
+        sb.append(last);
+        return sb.toString();
+    }
+
     /**
      * Translate the keyboard press to a VT100, VT220, or XTERM sequence.
      *
@@ -1311,69 +1351,177 @@ public class ECMA48 implements Runnable {
             }
         }
 
-        if (keypress.equals(kbLeft)) {
-            switch (arrowKeyMode) {
-            case ANSI:
-                return "\033[D";
-            case VT52:
-                return "\033D";
-            case VT100:
-                return "\033OD";
+        if (keypress.equalsWithoutModifiers(kbLeft)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '1', 'D',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '1', 'D',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '1', 'D',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return "\033[D";
+                case VT52:
+                    return "\033D";
+                case VT100:
+                    return "\033OD";
+                }
             }
         }
 
-        if (keypress.equals(kbRight)) {
-            switch (arrowKeyMode) {
-            case ANSI:
-                return "\033[C";
-            case VT52:
-                return "\033C";
-            case VT100:
-                return "\033OC";
+        if (keypress.equalsWithoutModifiers(kbRight)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '1', 'C',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '1', 'C',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '1', 'C',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return "\033[C";
+                case VT52:
+                    return "\033C";
+                case VT100:
+                    return "\033OC";
+                }
             }
         }
 
-        if (keypress.equals(kbUp)) {
-            switch (arrowKeyMode) {
-            case ANSI:
-                return "\033[A";
-            case VT52:
-                return "\033A";
-            case VT100:
-                return "\033OA";
+        if (keypress.equalsWithoutModifiers(kbUp)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '1', 'A',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '1', 'A',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '1', 'A',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return "\033[A";
+                case VT52:
+                    return "\033A";
+                case VT100:
+                    return "\033OA";
+                }
             }
         }
 
-        if (keypress.equals(kbDown)) {
-            switch (arrowKeyMode) {
-            case ANSI:
-                return "\033[B";
-            case VT52:
-                return "\033B";
-            case VT100:
-                return "\033OB";
+        if (keypress.equalsWithoutModifiers(kbDown)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '1', 'B',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '1', 'B',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '1', 'B',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return "\033[B";
+                case VT52:
+                    return "\033B";
+                case VT100:
+                    return "\033OB";
+                }
             }
         }
 
-        if (keypress.equals(kbHome)) {
-            switch (arrowKeyMode) {
-            case ANSI:
-                return "\033[H";
-            case VT52:
-                return "\033H";
-            case VT100:
-                return "\033OH";
+        if (keypress.equalsWithoutModifiers(kbHome)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '1', 'H',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '1', 'H',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '1', 'H',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return "\033[H";
+                case VT52:
+                    return "\033H";
+                case VT100:
+                    return "\033OH";
+                }
             }
         }
 
-        if (keypress.equals(kbEnd)) {
-            switch (arrowKeyMode) {
-            case ANSI:
-                return "\033[F";
-            case VT52:
-                return "\033F";
-            case VT100:
-                return "\033OF";
+        if (keypress.equalsWithoutModifiers(kbEnd)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '1', 'F',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '1', 'F',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '1', 'F',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return "\033[F";
+                case VT52:
+                    return "\033F";
+                case VT100:
+                    return "\033OF";
+                }
             }
         }
 
@@ -1500,6 +1648,9 @@ public class ECMA48 implements Runnable {
             if (vt52Mode) {
                 return "\0332P";
             }
+            if (type == DeviceType.XTERM) {
+                return "\0331;2P";
+            }
             return "\033O2P";
         }
 
@@ -1508,6 +1659,9 @@ public class ECMA48 implements Runnable {
             if (vt52Mode) {
                 return "\0332Q";
             }
+            if (type == DeviceType.XTERM) {
+                return "\0331;2Q";
+            }
             return "\033O2Q";
         }
 
@@ -1516,6 +1670,9 @@ public class ECMA48 implements Runnable {
             if (vt52Mode) {
                 return "\0332R";
             }
+            if (type == DeviceType.XTERM) {
+                return "\0331;2R";
+            }
             return "\033O2R";
         }
 
@@ -1524,6 +1681,9 @@ public class ECMA48 implements Runnable {
             if (vt52Mode) {
                 return "\0332S";
             }
+            if (type == DeviceType.XTERM) {
+                return "\0331;2S";
+            }
             return "\033O2S";
         }
 
@@ -1572,6 +1732,9 @@ public class ECMA48 implements Runnable {
             if (vt52Mode) {
                 return "\0335P";
             }
+            if (type == DeviceType.XTERM) {
+                return "\0331;5P";
+            }
             return "\033O5P";
         }
 
@@ -1580,6 +1743,9 @@ public class ECMA48 implements Runnable {
             if (vt52Mode) {
                 return "\0335Q";
             }
+            if (type == DeviceType.XTERM) {
+                return "\0331;5Q";
+            }
             return "\033O5Q";
         }
 
@@ -1588,6 +1754,9 @@ public class ECMA48 implements Runnable {
             if (vt52Mode) {
                 return "\0335R";
             }
+            if (type == DeviceType.XTERM) {
+                return "\0331;5R";
+            }
             return "\033O5R";
         }
 
@@ -1596,6 +1765,9 @@ public class ECMA48 implements Runnable {
             if (vt52Mode) {
                 return "\0335S";
             }
+            if (type == DeviceType.XTERM) {
+                return "\0331;5S";
+            }
             return "\033O5S";
         }
 
@@ -1639,39 +1811,93 @@ public class ECMA48 implements Runnable {
             return "\033[24;5~";
         }
 
-        if (keypress.equals(kbPgUp)) {
-            // Page Up
-            return "\033[5~";
-        }
-
-        if (keypress.equals(kbPgDn)) {
-            // Page Down
-            return "\033[6~";
-        }
-
-        if (keypress.equals(kbIns)) {
-            // Ins
-            return "\033[2~";
+        if (keypress.equalsWithoutModifiers(kbPgUp)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '5', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '5', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '5', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                return "\033[5~";
+            }
         }
 
-        if (keypress.equals(kbShiftIns)) {
-            // This is what xterm sends for SHIFT-INS
-            return "\033[2;2~";
-            // This is what xterm sends for CTRL-INS
-            // return "\033[2;5~";
+        if (keypress.equalsWithoutModifiers(kbPgDn)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '6', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '6', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '6', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                return "\033[6~";
+            }
         }
 
-        if (keypress.equals(kbShiftDel)) {
-            // This is what xterm sends for SHIFT-DEL
-            return "\033[3;2~";
-            // This is what xterm sends for CTRL-DEL
-            // return "\033[3;5~";
+        if (keypress.equalsWithoutModifiers(kbIns)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '2', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '2', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '2', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                return "\033[2~";
+            }
         }
 
-        if (keypress.equals(kbDel)) {
-            // Delete sends real delete for VTxxx
-            return "\177";
-            // return "\033[3~";
+        if (keypress.equalsWithoutModifiers(kbDel)) {
+            switch (type) {
+            case XTERM:
+                switch (arrowKeyMode) {
+                case ANSI:
+                    return xtermBuildKeySequence("\033[", '3', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT52:
+                    return xtermBuildKeySequence("\033", '3', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                case VT100:
+                    return xtermBuildKeySequence("\033O", '3', '~',
+                        keypress.isCtrl(), keypress.isAlt(),
+                        keypress.isShift());
+                }
+            default:
+                // Delete sends real delete for VTxxx
+                return "\177";
+            }
         }
 
         if (keypress.equals(kbEnter)) {