misc cleanup
[fanfix.git] / src / jexer / io / ECMA48Terminal.java
index b8fabda389b5253d10bf5ed0a1b91199eee37bff..d466646d5d129b312a8d93aa85c61812502738ec 100644 (file)
@@ -61,7 +61,7 @@ import static jexer.TKeypress.*;
  * This class reads keystrokes and mouse events and emits output to ANSI
  * X3.64 / ECMA-48 type terminals e.g. xterm, linux, vt100, ansi.sys, etc.
  */
-public class ECMA48Terminal implements Runnable {
+public final class ECMA48Terminal implements Runnable {
 
     /**
      * The session information.
@@ -73,7 +73,7 @@ public class ECMA48Terminal implements Runnable {
      *
      * @return the SessionInfo
      */
-    public final SessionInfo getSessionInfo() {
+    public SessionInfo getSessionInfo() {
         return sessionInfo;
     }
 
@@ -127,6 +127,12 @@ public class ECMA48Terminal implements Runnable {
      */
     private long escapeTime;
 
+    /**
+     * The time we last checked the window size.  We try not to spawn stty
+     * more than once per second.
+     */
+    private long windowSizeTime;
+
     /**
      * true if mouse1 was down.  Used to report mouse1 on the release event.
      */
@@ -243,7 +249,7 @@ public class ECMA48Terminal implements Runnable {
         };
         try {
             Process process;
-            if (mode == true) {
+            if (mode) {
                 process = Runtime.getRuntime().exec(cmdRaw);
             } else {
                 process = Runtime.getRuntime().exec(cmdCooked);
@@ -474,7 +480,7 @@ public class ECMA48Terminal implements Runnable {
             // Unknown modifier, bail out
             return null;
         }
-        
+
         switch (key) {
         case 1:
             return new TKeypressEvent(kbHome, alt, ctrl, shift);
@@ -530,97 +536,100 @@ public class ECMA48Terminal implements Runnable {
             y = windowResize.getHeight() - 1;
         }
 
-        TMouseEvent event = new TMouseEvent(TMouseEvent.Type.MOUSE_DOWN);
-        event.x = x;
-        event.y = y;
-        event.absoluteX = x;
-        event.absoluteY = y;
+        TMouseEvent.Type eventType = TMouseEvent.Type.MOUSE_DOWN;
+        boolean eventMouse1 = false;
+        boolean eventMouse2 = false;
+        boolean eventMouse3 = false;
+        boolean eventMouseWheelUp = false;
+        boolean eventMouseWheelDown = false;
 
         // System.err.printf("buttons: %04x\r\n", buttons);
 
         switch (buttons) {
         case 0:
-            event.mouse1 = true;
+            eventMouse1 = true;
             mouse1 = true;
             break;
         case 1:
-            event.mouse2 = true;
+            eventMouse2 = true;
             mouse2 = true;
             break;
         case 2:
-            event.mouse3 = true;
+            eventMouse3 = true;
             mouse3 = true;
             break;
         case 3:
             // Release or Move
             if (!mouse1 && !mouse2 && !mouse3) {
-                event.type = TMouseEvent.Type.MOUSE_MOTION;
+                eventType = TMouseEvent.Type.MOUSE_MOTION;
             } else {
-                event.type = TMouseEvent.Type.MOUSE_UP;
+                eventType = TMouseEvent.Type.MOUSE_UP;
             }
             if (mouse1) {
                 mouse1 = false;
-                event.mouse1 = true;
+                eventMouse1 = true;
             }
             if (mouse2) {
                 mouse2 = false;
-                event.mouse2 = true;
+                eventMouse2 = true;
             }
             if (mouse3) {
                 mouse3 = false;
-                event.mouse3 = true;
+                eventMouse3 = true;
             }
             break;
 
         case 32:
             // Dragging with mouse1 down
-            event.mouse1 = true;
+            eventMouse1 = true;
             mouse1 = true;
-            event.type = TMouseEvent.Type.MOUSE_MOTION;
+            eventType = TMouseEvent.Type.MOUSE_MOTION;
             break;
 
         case 33:
             // Dragging with mouse2 down
-            event.mouse2 = true;
+            eventMouse2 = true;
             mouse2 = true;
-            event.type = TMouseEvent.Type.MOUSE_MOTION;
+            eventType = TMouseEvent.Type.MOUSE_MOTION;
             break;
 
         case 34:
             // Dragging with mouse3 down
-            event.mouse3 = true;
+            eventMouse3 = true;
             mouse3 = true;
-            event.type = TMouseEvent.Type.MOUSE_MOTION;
+            eventType = TMouseEvent.Type.MOUSE_MOTION;
             break;
 
         case 96:
             // Dragging with mouse2 down after wheelUp
-            event.mouse2 = true;
+            eventMouse2 = true;
             mouse2 = true;
-            event.type = TMouseEvent.Type.MOUSE_MOTION;
+            eventType = TMouseEvent.Type.MOUSE_MOTION;
             break;
 
         case 97:
             // Dragging with mouse2 down after wheelDown
-            event.mouse2 = true;
+            eventMouse2 = true;
             mouse2 = true;
-            event.type = TMouseEvent.Type.MOUSE_MOTION;
+            eventType = TMouseEvent.Type.MOUSE_MOTION;
             break;
 
         case 64:
-            event.mouseWheelUp = true;
+            eventMouseWheelUp = true;
             break;
 
         case 65:
-            event.mouseWheelDown = true;
+            eventMouseWheelDown = true;
             break;
 
         default:
             // Unknown, just make it motion
-            event.type = TMouseEvent.Type.MOUSE_MOTION;
+            eventType = TMouseEvent.Type.MOUSE_MOTION;
             break;
         }
-        return event;
+        return new TMouseEvent(eventType, x, y, x, y,
+            eventMouse1, eventMouse2, eventMouse3,
+            eventMouseWheelUp, eventMouseWheelDown);
     }
 
     /**
@@ -631,7 +640,9 @@ public class ECMA48Terminal implements Runnable {
     public void getEvents(final List<TInputEvent> queue) {
         synchronized (eventQueue) {
             if (eventQueue.size() > 0) {
-                queue.addAll(eventQueue);
+                synchronized (queue) {
+                    queue.addAll(eventQueue);
+                }
                 eventQueue.clear();
             }
         }
@@ -642,28 +653,34 @@ public class ECMA48Terminal implements Runnable {
      *
      * @param queue list to append new events to
      */
-    public void getIdleEvents(final List<TInputEvent> queue) {
+    private void getIdleEvents(final List<TInputEvent> queue) {
+        Date now = new Date();
 
         // Check for new window size
-        sessionInfo.queryWindowSize();
-        int newWidth = sessionInfo.getWindowWidth();
-        int newHeight = sessionInfo.getWindowHeight();
-        if ((newWidth != windowResize.getWidth())
-            || (newHeight != windowResize.getHeight())
-        ) {
-            TResizeEvent event = new TResizeEvent(TResizeEvent.Type.SCREEN,
-                newWidth, newHeight);
-            windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN,
-                newWidth, newHeight);
-            synchronized (eventQueue) {
-                eventQueue.add(event);
+        long windowSizeDelay = now.getTime() - windowSizeTime;
+        if (windowSizeDelay > 1000) {
+            sessionInfo.queryWindowSize();
+            int newWidth = sessionInfo.getWindowWidth();
+            int newHeight = sessionInfo.getWindowHeight();
+            if ((newWidth != windowResize.getWidth())
+                || (newHeight != windowResize.getHeight())
+            ) {
+                TResizeEvent event = new TResizeEvent(TResizeEvent.Type.SCREEN,
+                    newWidth, newHeight);
+                windowResize = new TResizeEvent(TResizeEvent.Type.SCREEN,
+                    newWidth, newHeight);
+                queue.add(event);
             }
+            windowSizeTime = now.getTime();
         }
 
-        synchronized (eventQueue) {
-            if (eventQueue.size() > 0) {
-                queue.addAll(eventQueue);
-                eventQueue.clear();
+        // ESCDELAY type timeout
+        if (state == ParseState.ESCAPE) {
+            long escDelay = now.getTime() - escapeTime;
+            if (escDelay > 100) {
+                // After 0.1 seconds, assume a true escape character
+                queue.add(controlChar((char)0x1B, false));
+                reset();
             }
         }
     }
@@ -789,7 +806,7 @@ public class ECMA48Terminal implements Runnable {
             // Parameter separator
             if (ch == ';') {
                 paramI++;
-                params.set(paramI, "");
+                params.add("");
                 return;
             }
 
@@ -897,7 +914,7 @@ public class ECMA48Terminal implements Runnable {
             // Parameter separator
             if (ch == ';') {
                 paramI++;
-                params.set(paramI, "");
+                params.add(paramI, "");
                 return;
             }
 
@@ -1442,8 +1459,16 @@ public class ECMA48Terminal implements Runnable {
                         }
                     }
                 } else {
-                    // Wait 5 millis for more data
-                    Thread.sleep(5);
+                    getIdleEvents(events);
+                    if (events.size() > 0) {
+                        synchronized (eventQueue) {
+                            eventQueue.addAll(events);
+                        }
+                        events.clear();
+                    }
+
+                    // Wait 10 millis for more data
+                    Thread.sleep(10);
                 }
                 // System.err.println("end while loop"); System.err.flush();
             } catch (InterruptedException e) {