Support for Xterm ctrl/alt/shift function keys
[fanfix.git] / src / jexer / io / ECMA48Terminal.java
index 8e1a03dd7d7158ec2e91b076a615758f041b542d..069c143f2d32e9a8c6f86dc474ac2149df6f2244 100644 (file)
@@ -1,29 +1,27 @@
-/**
+/*
  * Jexer - Java Text User Interface
  *
- * License: LGPLv3 or later
- *
- * This module is licensed under the GNU Lesser General Public License
- * Version 3.  Please see the file "COPYING" in this directory for more
- * information about the GNU Lesser General Public License Version 3.
+ * The MIT License (MIT)
  *
- *     Copyright (C) 2015  Kevin Lamonte
+ * Copyright (C) 2016 Kevin Lamonte
  *
- * This program 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.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
  *
- * This program 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
- * General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, see
- * http://www.gnu.org/licenses/, or write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
  *
  * @author Kevin Lamonte [kevin.lamonte@gmail.com]
  * @version 1
@@ -106,7 +104,6 @@ public final class ECMA48Terminal implements Runnable {
         ESCAPE_INTERMEDIATE,
         CSI_ENTRY,
         CSI_PARAM,
-        // CSI_INTERMEDIATE,
         MOUSE,
         MOUSE_SGR,
     }
@@ -444,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) {
@@ -779,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.
@@ -906,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;
@@ -1063,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();
@@ -1079,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();
@@ -1095,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();
@@ -1111,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;
                 }
@@ -1406,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";
     }
 
     /**