Rename AWT to Swing
authorKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 21 Mar 2015 23:14:34 +0000 (19:14 -0400)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Sat, 21 Mar 2015 23:14:34 +0000 (19:14 -0400)
README.md
build.xml
src/jexer/TApplication.java
src/jexer/backend/SwingBackend.java [moved from src/jexer/backend/AWTBackend.java with 84% similarity]
src/jexer/demos/Demo1.java
src/jexer/io/SwingScreen.java [moved from src/jexer/io/AWTScreen.java with 93% similarity]
src/jexer/io/SwingTerminal.java [moved from src/jexer/io/AWTTerminal.java with 97% similarity]
src/jexer/session/SwingSessionInfo.java [moved from src/jexer/session/AWTSessionInfo.java with 91% similarity]
src/jexer/session/TTYSessionInfo.java

index af877888f665d3cd8af02457bc73cc7b64bd3457..4acc5251ebc7433a151b74a65c60227889c7fe3f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
 Jexer - Java Text User Interface library
 ========================================
 
-WARNING: THIS IS ALPHA CODE!
+WARNING: THIS IS ALPHA CODE!  PLEASE CONSIDER FILING BUGS AS YOU
+ENCOUNTER THEM.
 
 This library is intended to implement a text-based windowing system
 loosely reminiscient of Borland's [Turbo
@@ -16,16 +17,20 @@ Two backends are available:
   (tested on Linux + xterm).  I/O is handled through terminal escape
   sequences generated by the library itself: ncurses is not required
   or linked to.  xterm mouse tracking using UTF8 coordinates is
-  supported.  This is the default backend on non-Windows platforms.
+  supported.  For the demo application, this is the default backend on
+  non-Windows platforms.
 
-* Java AWT UI.  This backend can be selected by setting
-  jexer.AWT=true.  This is the default backend on Windows platforms.
-  AWT is experimental, please consider filing bugs when you encounter
-  them.  The default window size for AWT is 132x40, which is set in
-  jexer.session.AWTSession.
+* Java Swing UI.  This backend can be selected by setting
+  jexer.Swing=true.  The default window size for Swing is 132x40,
+  which is set in jexer.session.SwingSession.  For the demo
+  application, this is the default backend on Windows platforms.
 
-A demo application showing the existing UI controls is available via
-'java -jar jexer.jar' or 'java -Djexer.AWT=true -jar jexer.jar' .
+The demo application showing the existing UI controls is available via
+'java -jar jexer.jar' or 'java -Djexer.Swing=true -jar jexer.jar' .
+
+Additional backends can be created by subclassing
+jexer.backend.Backend and passing it into the TApplication
+constructor.
 
 
 
@@ -55,7 +60,7 @@ Usage
 -----
 
 Usage patterns are still being worked on, but in general the goal will
-be to build applications somewhat as follows:
+be to build applications as follows:
 
 ```Java
 import jexer.*;
@@ -63,7 +68,7 @@ import jexer.*;
 public class MyApplication extends TApplication {
 
     public MyApplication() {
-        super();
+        super(BackendType.SWING); // Could also use BackendType.XTERM
 
         // Create standard menus for File and Window
         addFileMenu();
@@ -72,7 +77,7 @@ public class MyApplication extends TApplication {
 
     public static void main(String [] args) {
         MyApplication app = new MyApplication();
-        app.run();
+        (new Thread(app)).start();
     }
 }
 ```
@@ -100,6 +105,10 @@ ambiguous.  This section describes such issues.
   - See jexer.tterminal.ECMA48 for more specifics of terminal
     emulation limitations.
 
+  - TTerminalWindow uses cmd.exe on Windows.  Output will not be seen
+    until enter is pressed, due to cmd.exe's use of line-oriented
+    input (see the ENABLE_LINE_INPUT flag for GetConsoleMode() and
+    SetConsoleMode()).
 
 
 
@@ -108,15 +117,14 @@ Roadmap
 
 Many tasks remain before calling this version 1.0:
 
-0.0.2:
+0.0.2: STABILIZE EXISTING
 
-- Making TMenu keyboard accelerators active/inactive
-- AWT:
+- TTerminalWindow
+  - Expose shell commands as properties
+- Swing:
   - Blinking cursor
   - Block cursor
 - ECMA48Backend running on socket
-- TTreeView
-- TDirectoryList
 - TFileOpen
 - Decide on naming convention: getText, getValue, getLabel: one or all
   of them?
@@ -125,24 +133,35 @@ Many tasks remain before calling this version 1.0:
     - getCh() --> getChar()
     - getAlt/getCtrl/getShift --> isAltDown / isCtrlDown / isShiftDown
   - Other boolean getters --> isSomething
+- Document any properties used
+  - Expose use of 'stty'
+
+0.0.3: FINISH PORTING
 
-0.0.3:
+- TTreeView
+  - Also add keyboard navigation
+- TDirectoryList
+  - Also add keyboard navigation
+
+0.0.4: NEW STUFF
 
+- Making TMenu keyboard accelerators active/inactive
 - TStatusBar
 - TEditor
+- TWindow
+  - "Smart placement" for new windows
 
-0.0.4:
+0.0.5: BUG HUNT
 
-- Bugs
-  - TSubMenu keyboard mnemonic not working
-  - TDirectoryList cannot be navigated only with keyboard
-  - TTreeView cannot be navigated only with keyboard
-  - RangeViolation after dragging scrollbar up/down
+- TSubMenu keyboard mnemonic not working
 
-0.1.0:
+0.1.0: BETA RELEASE
 
-- TWindow
-  - "Smart placement" for new windows
+- TSpinner
+- TComboBox
+- TListBox
+- TCalendar
+- TColorPicker
 
 Wishlist features (2.0):
 
@@ -150,11 +169,6 @@ Wishlist features (2.0):
   - Handle resize events (pass to child process)
 - Screen
   - Allow complex characters in putCharXY() and detect them in putStrXY().
-- TComboBox
-- TListBox
-- TSpinner
-- TCalendar widget
-- TColorPicker widget
 - Drag and drop
   - TEditor
   - TField
index 35d82d30a05a652726d68bfb79f6b469751722b5..2641c5a7dfb75eaf289eb1f46424540066bc15d8 100644 (file)
--- a/build.xml
+++ b/build.xml
     <property name="build.dir"     value="build"/>
     <property name="classes.dir"   value="${build.dir}/classes"/>
     <property name="jar.dir"       value="${build.dir}/jar"/>
+    <property name="apidocs.dir"   value="docs/api"/>
 
     <target name="clean">
        <delete dir="${build.dir}"/>
+       <delete dir="${apidocs.dir}"/>
     </target>
 
     <target name="compile">
@@ -62,7 +64,7 @@
 
     <target name="run" depends="jar">
       <java jar="${jar.dir}/${ant.project.name}.jar" fork="true">
-       <arg value="-Djexer.AWT=true"/>
+       <arg value="-Djexer.Swing=true"/>
       </java>
     </target>
 
@@ -74,7 +76,7 @@
 
     <target name="docs" depends="jar">
       <javadoc
-         destdir="docs/api"
+         destdir="${apidocs.dir}"
          author="true"
          version="true"
          use="true"
index 6bec9006c9a2e95ee057a7d042b61666e354b322..2b8f47e47cbf80b84cdd5bb83ce90c7bdfa2846f 100644 (file)
@@ -51,7 +51,7 @@ import jexer.event.TMenuEvent;
 import jexer.event.TMouseEvent;
 import jexer.event.TResizeEvent;
 import jexer.backend.Backend;
-import jexer.backend.AWTBackend;
+import jexer.backend.SwingBackend;
 import jexer.backend.ECMA48Backend;
 import jexer.io.Screen;
 import jexer.menu.TMenu;
@@ -61,7 +61,7 @@ import static jexer.TCommand.*;
 /**
  * TApplication sets up a full Text User Interface application.
  */
-public class TApplication {
+public class TApplication implements Runnable {
 
     /**
      * If true, emit thread stuff to System.err.
@@ -73,6 +73,26 @@ public class TApplication {
      */
     private static final boolean debugEvents = false;
 
+    /**
+     * Two backend types are available.
+     */
+    public static enum BackendType {
+        /**
+         * A Swing JFrame.
+         */
+        SWING,
+
+        /**
+         * An ECMA48 / ANSI X3.64 / XTERM style terminal.
+         */
+        ECMA48,
+
+        /**
+         * Synonym for ECMA48
+         */
+        XTERM
+    }
+
     /**
      * WidgetEventHandler is the main event consumer loop.  There are at most
      * two such threads in existence: the primary for normal case and a
@@ -461,6 +481,29 @@ public class TApplication {
     /**
      * Public constructor.
      *
+     * @param backendType BackendType.XTERM, BackendType.ECMA48 or
+     * BackendType.SWING
+     * @throws UnsupportedEncodingException if an exception is thrown when
+     * creating the InputStreamReader
+     */
+    public TApplication(final BackendType backendType)
+        throws UnsupportedEncodingException {
+
+        switch (backendType) {
+        case SWING:
+            backend = new SwingBackend(this);
+            break;
+        case XTERM:
+            // Fall through...
+        case ECMA48:
+            backend = new ECMA48Backend(this, null, null);
+        }
+        TApplicationImpl();
+    }
+
+    /**
+     * Public constructor.  The backend type will be BackendType.ECMA48.
+     *
      * @param input an InputStream connected to the remote user, or null for
      * System.in.  If System.in is used, then on non-Windows systems it will
      * be put in raw mode; shutdown() will (blindly!) put System.in in cooked
@@ -474,26 +517,25 @@ public class TApplication {
     public TApplication(final InputStream input,
         final OutputStream output) throws UnsupportedEncodingException {
 
-        // AWT is the default backend on Windows unless explicitly overridden
-        // by jexer.AWT.
-        boolean useAWT = false;
-        if (System.getProperty("os.name").startsWith("Windows")) {
-            useAWT = true;
-        }
-        if (System.getProperty("jexer.AWT") != null) {
-            if (System.getProperty("jexer.AWT", "false").equals("true")) {
-                useAWT = true;
-            } else {
-                useAWT = false;
-            }
-        }
+        backend = new ECMA48Backend(this, input, output);
+        TApplicationImpl();
+    }
 
+    /**
+     * Public constructor.  This hook enables use with new non-Jexer
+     * backends.
+     *
+     * @param backend a Backend that is already ready to go.
+     */
+    public TApplication(final Backend backend) {
+        this.backend = backend;
+        TApplicationImpl();
+    }
 
-        if (useAWT) {
-            backend     = new AWTBackend(this);
-        } else {
-            backend     = new ECMA48Backend(this, input, output);
-        }
+    /**
+     * Finish construction once the backend is set.
+     */
+    private void TApplicationImpl() {
         theme           = new ColorTheme();
         desktopBottom   = getScreen().getHeight() - 1;
         fillEventQueue  = new ArrayList<TInputEvent>();
@@ -638,7 +680,7 @@ public class TApplication {
     /**
      * Run this application until it exits.
      */
-    public final void run() {
+    public void run() {
         while (!quit) {
             // Timeout is in milliseconds, so default timeout after 1 second
             // of inactivity.
similarity index 84%
rename from src/jexer/backend/AWTBackend.java
rename to src/jexer/backend/SwingBackend.java
index af2d181a6343da5eef95ce3a66995e070adcc1a0..3f95866fe2b3737c4f2a53ec11ad4bb1ddb89dd3 100644 (file)
@@ -33,19 +33,19 @@ package jexer.backend;
 import java.util.List;
 
 import jexer.event.TInputEvent;
-import jexer.io.AWTScreen;
-import jexer.io.AWTTerminal;
+import jexer.io.SwingScreen;
+import jexer.io.SwingTerminal;
 
 /**
- * This class uses standard AWT calls to handle screen, keyboard, and mouse
+ * This class uses standard Swing calls to handle screen, keyboard, and mouse
  * I/O.
  */
-public final class AWTBackend extends Backend {
+public final class SwingBackend extends Backend {
 
     /**
      * Input events are processed by this Terminal.
      */
-    private AWTTerminal terminal;
+    private SwingTerminal terminal;
 
     /**
      * Public constructor.
@@ -53,13 +53,13 @@ public final class AWTBackend extends Backend {
      * @param listener the object this backend needs to wake up when new
      * input comes in
      */
-    public AWTBackend(final Object listener) {
+    public SwingBackend(final Object listener) {
         // Create a screen
-        AWTScreen screen = new AWTScreen();
+        SwingScreen screen = new SwingScreen();
         this.screen = screen;
 
-        // Create the AWT event listeners
-        terminal = new AWTTerminal(listener, screen);
+        // Create the Swing event listeners
+        terminal = new SwingTerminal(listener, screen);
 
         // Hang onto the session info
         this.sessionInfo = terminal.getSessionInfo();
index 1afa354c7aebcb9aa34416ba1f999acb2a6bb39d..32272fbe62158e78f48d7d02006d338b2ec78192 100644 (file)
@@ -446,10 +446,11 @@ class DemoApplication extends TApplication {
     /**
      * Public constructor.
      *
+     * @param backendType one of the TApplication.BackendType values
      * @throws Exception if TApplication can't instantiate the Backend.
      */
-    public DemoApplication() throws Exception {
-        super(null, null);
+    public DemoApplication(BackendType backendType) throws Exception {
+        super(backendType);
         new DemoMainWindow(this);
 
         // Add the menus
@@ -494,8 +495,21 @@ public class Demo1 {
      */
     public static void main(final String [] args) {
         try {
-            DemoApplication app = new DemoApplication();
-            app.run();
+            // Swing is the default backend on Windows unless explicitly
+            // overridden by jexer.Swing.
+            TApplication.BackendType backendType = TApplication.BackendType.XTERM;
+            if (System.getProperty("os.name").startsWith("Windows")) {
+                backendType = TApplication.BackendType.SWING;
+            }
+            if (System.getProperty("jexer.Swing") != null) {
+                if (System.getProperty("jexer.Swing", "false").equals("true")) {
+                    backendType = TApplication.BackendType.SWING;
+                } else {
+                    backendType = TApplication.BackendType.XTERM;
+                }
+            }
+            DemoApplication app = new DemoApplication(backendType);
+            (new Thread(app)).start();
         } catch (Exception e) {
             e.printStackTrace();
         }
similarity index 93%
rename from src/jexer/io/AWTScreen.java
rename to src/jexer/io/SwingScreen.java
index 208bea356496334386bf2ee0cd02b2172cdcdbe7..e06dc83d82212d059c1c709ee613f882f53165b6 100644 (file)
@@ -32,7 +32,7 @@ package jexer.io;
 
 import jexer.bits.Cell;
 import jexer.bits.CellAttributes;
-import jexer.session.AWTSessionInfo;
+import jexer.session.SwingSessionInfo;
 
 import java.awt.Color;
 import java.awt.Cursor;
@@ -50,9 +50,9 @@ import javax.swing.JFrame;
 import javax.swing.SwingUtilities;
 
 /**
- * This Screen implementation draws to a Java AWT Frame.
+ * This Screen implementation draws to a Java Swing JFrame.
  */
-public final class AWTScreen extends Screen {
+public final class SwingScreen extends Screen {
 
     private static Color MYBLACK;
     private static Color MYRED;
@@ -75,7 +75,7 @@ public final class AWTScreen extends Screen {
     private static boolean dosColors = false;
 
     /**
-     * Setup AWT colors to match DOS color palette.
+     * Setup Swing colors to match DOS color palette.
      */
     private static void setDOSColors() {
         if (dosColors) {
@@ -102,9 +102,9 @@ public final class AWTScreen extends Screen {
     }
 
     /**
-     * AWTFrame is our top-level hook into the AWT system.
+     * SwingFrame is our top-level hook into the Swing system.
      */
-    class AWTFrame extends JFrame {
+    class SwingFrame extends JFrame {
 
         /**
          * Serializable version.
@@ -119,7 +119,7 @@ public final class AWTScreen extends Screen {
         /**
          * The TUI Screen data.
          */
-        AWTScreen screen;
+        SwingScreen screen;
 
         /**
          * Width of a character cell.
@@ -147,10 +147,10 @@ public final class AWTScreen extends Screen {
         private int left = 30;
 
         /**
-         * Convert a CellAttributes foreground color to an AWT Color.
+         * Convert a CellAttributes foreground color to an Swing Color.
          *
          * @param attr the text attributes
-         * @return the AWT Color
+         * @return the Swing Color
          */
         private Color attrToForegroundColor(final CellAttributes attr) {
             /*
@@ -200,10 +200,10 @@ public final class AWTScreen extends Screen {
         }
 
         /**
-         * Convert a CellAttributes background color to an AWT Color.
+         * Convert a CellAttributes background color to an Swing Color.
          *
          * @param attr the text attributes
-         * @return the AWT Color
+         * @return the Swing Color
          */
         private Color attrToBackgroundColor(final CellAttributes attr) {
             /*
@@ -237,7 +237,7 @@ public final class AWTScreen extends Screen {
          *
          * @param screen the Screen that Backend talks to
          */
-        public AWTFrame(final AWTScreen screen) {
+        public SwingFrame(final SwingScreen screen) {
             this.screen = screen;
             setDOSColors();
 
@@ -310,7 +310,7 @@ public final class AWTScreen extends Screen {
         /**
          * Update redraws the whole screen.
          *
-         * @param gr the AWT Graphics context
+         * @param gr the Swing Graphics context
          */
         @Override
         public void update(final Graphics gr) {
@@ -322,7 +322,7 @@ public final class AWTScreen extends Screen {
         /**
          * Paint redraws the whole screen.
          *
-         * @param gr the AWT Graphics context
+         * @param gr the Swing Graphics context
          */
         @Override
         public void paint(final Graphics gr) {
@@ -420,31 +420,31 @@ public final class AWTScreen extends Screen {
             } // synchronized (screen)
         }
 
-    } // class AWTFrame
+    } // class SwingFrame
 
     /**
-     * The raw AWT Frame.  Note package private access.
+     * The raw Swing JFrame.  Note package private access.
      */
-    AWTFrame frame;
+    SwingFrame frame;
 
     /**
      * Public constructor.
      */
-    public AWTScreen() {
+    public SwingScreen() {
         try {
             SwingUtilities.invokeAndWait(new Runnable() {
                 public void run() {
-                    AWTScreen.this.frame = new AWTFrame(AWTScreen.this);
-                    AWTScreen.this.sessionInfo =
-                        new AWTSessionInfo(AWTScreen.this.frame,
+                    SwingScreen.this.frame = new SwingFrame(SwingScreen.this);
+                    SwingScreen.this.sessionInfo =
+                        new SwingSessionInfo(SwingScreen.this.frame,
                             frame.textWidth,
                             frame.textHeight);
 
-                    AWTScreen.this.setDimensions(sessionInfo.getWindowWidth(),
+                    SwingScreen.this.setDimensions(sessionInfo.getWindowWidth(),
                         sessionInfo.getWindowHeight());
 
-                    AWTScreen.this.frame.resizeToScreen();
-                    AWTScreen.this.frame.setVisible(true);
+                    SwingScreen.this.frame.resizeToScreen();
+                    SwingScreen.this.frame.setVisible(true);
                 }
             } );
         } catch (Exception e) {
@@ -455,14 +455,14 @@ public final class AWTScreen extends Screen {
     /**
      * The sessionInfo.
      */
-    private AWTSessionInfo sessionInfo;
+    private SwingSessionInfo sessionInfo;
 
     /**
-     * Create the AWTSessionInfo.  Note package private access.
+     * Create the SwingSessionInfo.  Note package private access.
      *
      * @return the sessionInfo
      */
-    AWTSessionInfo getSessionInfo() {
+    SwingSessionInfo getSessionInfo() {
         return sessionInfo;
     }
 
similarity index 97%
rename from src/jexer/io/AWTTerminal.java
rename to src/jexer/io/SwingTerminal.java
index 8b542402daf5b7321de855fbeffd8d31f09559c7..3f3d8e3976246becca2043c69c4a888d1a06b3cf 100644 (file)
@@ -51,26 +51,26 @@ import jexer.event.TKeypressEvent;
 import jexer.event.TMouseEvent;
 import jexer.event.TResizeEvent;
 import jexer.session.SessionInfo;
-import jexer.session.AWTSessionInfo;
+import jexer.session.SwingSessionInfo;
 import static jexer.TCommand.*;
 import static jexer.TKeypress.*;
 
 /**
- * This class reads keystrokes and mouse events from an AWT Frame.
+ * This class reads keystrokes and mouse events from an Swing JFrame.
  */
-public final class AWTTerminal implements ComponentListener, KeyListener,
+public final class SwingTerminal implements ComponentListener, KeyListener,
                                MouseListener, MouseMotionListener,
                                MouseWheelListener, WindowListener {
 
     /**
      * The backend Screen.
      */
-    private AWTScreen screen;
+    private SwingScreen screen;
 
     /**
      * The session information.
      */
-    private AWTSessionInfo sessionInfo;
+    private SwingSessionInfo sessionInfo;
 
     /**
      * Getter for sessionInfo.
@@ -132,9 +132,9 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
      *
      * @param listener the object this backend needs to wake up when new
      * input comes in
-     * @param screen the top-level AWT frame
+     * @param screen the top-level Swing frame
      */
-    public AWTTerminal(final Object listener, final AWTScreen screen) {
+    public SwingTerminal(final Object listener, final SwingScreen screen) {
         this.listener    = listener;
         this.screen      = screen;
         mouse1           = false;
@@ -176,7 +176,7 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
     }
 
     /**
-     * Pass AWT keystrokes into the event queue.
+     * Pass Swing keystrokes into the event queue.
      *
      * @param key keystroke received
      */
@@ -186,7 +186,7 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
     }
 
     /**
-     * Pass AWT keystrokes into the event queue.
+     * Pass Swing keystrokes into the event queue.
      *
      * @param key keystroke received
      */
@@ -196,7 +196,7 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
     }
 
     /**
-     * Pass AWT keystrokes into the event queue.
+     * Pass Swing keystrokes into the event queue.
      *
      * @param key keystroke received
      */
@@ -217,7 +217,7 @@ public final class AWTTerminal implements ComponentListener, KeyListener,
         shift = key.isShiftDown();
 
         /*
-        System.err.printf("AWT Key: %s\n", key);
+        System.err.printf("Swing Key: %s\n", key);
         System.err.printf("   isKey: %s\n", isKey);
         System.err.printf("   alt: %s\n", alt);
         System.err.printf("   ctrl: %s\n", ctrl);
similarity index 91%
rename from src/jexer/session/AWTSessionInfo.java
rename to src/jexer/session/SwingSessionInfo.java
index 1c9bf97aaf22da574d7d9bb9f34fa7815d4e07e5..e263c7361200f1084e947ab08915ab2eea780b70 100644 (file)
@@ -34,14 +34,14 @@ import java.awt.Frame;
 import java.awt.Insets;
 
 /**
- * AWTSessionInfo provides a session implementation with a callback into an
- * AWT Frame to support queryWindowSize().  The username is blank, language
+ * SwingSessionInfo provides a session implementation with a callback into an
+ * Swing Frame to support queryWindowSize().  The username is blank, language
  * is "en_US", with a 132x40 text window.
  */
-public final class AWTSessionInfo implements SessionInfo {
+public final class SwingSessionInfo implements SessionInfo {
 
     /**
-     * The AWT Frame.
+     * The Swing Frame.
      */
     private Frame frame;
 
@@ -132,11 +132,11 @@ public final class AWTSessionInfo implements SessionInfo {
     /**
      * Public constructor.
      *
-     * @param frame the AWT Frame
+     * @param frame the Swing Frame
      * @param textWidth the width of a cell in pixels
      * @param textHeight the height of a cell in pixels
      */
-    public AWTSessionInfo(final Frame frame, final int textWidth,
+    public SwingSessionInfo(final Frame frame, final int textWidth,
         final int textHeight) {
 
         this.frame      = frame;
index 4716e26d6c050e4ff22d1beea8505f6d62863914..4df2811bc7b7b5739b01173a6392fe4789bc8b48 100644 (file)
@@ -38,9 +38,8 @@ import java.util.StringTokenizer;
 
 /**
  * TTYSessionInfo queries environment variables and the tty window size for
- * the session information.  The username is taken from
- * getpwuid(geteuid()).pw_name, language is taken from LANG, and text window
- * size from ioctl(TIOCGWINSIZ).
+ * the session information.  The username is taken from user.name, language
+ * is taken from user.language, and text window size from 'stty size'.
  */
 public final class TTYSessionInfo implements SessionInfo {