commit ef6cad1d6b21c1dcbcbef21861969aa85b54fa0b from: leo date: Wed Sep 8 16:59:25 1999 UTC Initial revision commit - e8dbb7eedfb0f9bd8407e0364bc6a309239c89f6 commit + ef6cad1d6b21c1dcbcbef21861969aa85b54fa0b blob - /dev/null blob + 57b7661b720a1b4a082494847edc4af1663cc840 (mode 644) --- /dev/null +++ Makefile @@ -0,0 +1,38 @@ +JAVA = java +JAR = jar +JAVAC = javac +DEBUG = -g -deprecation +JFLAGS = -classpath $(CLASSPATH):. +SRCDIR = de + +.SUFFIXES: .java .class + +# compile java files to class +.java.class: + $(JAVAC) $(DEBUG) $(JFLAGS) $< + +# +# major rules to create files +# +all: app doc jar + +doc: app + javadoc -d doc -version -author \ + `find de/mud -type d -print | \ + grep -v CVS | grep -v '^de/mud$$' | sed 's/\//./g'` + +run: app + $(JAVA) $(JFLAGS) de.mud.jta.Main + +jar: app + $(JAR) cvf jar/jta.jar `find $(SRCDIR) -name *.class` + +# +# application dependencies +# +app: + @find $(SRCDIR) -name \*.java | sed 's/java$$/class/' | xargs make + +clean: + -find . -name *.class -print | xargs rm > /dev/null 2>&1 + -find . -name *~ -print | xargs rm > /dev/null 2>&1 blob - /dev/null blob + 9dd433cc278852d40893a22cf85717e89e88e689 (mode 644) --- /dev/null +++ de/mud/jta/Common.java @@ -0,0 +1,100 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta; + +import de.mud.jta.PluginLoader; +import de.mud.jta.VisualPlugin; +import de.mud.jta.Plugin; +import de.mud.jta.event.ConfigurationRequest; +import de.mud.jta.event.SocketRequest; + +import java.util.Properties; +import java.util.Hashtable; +import java.util.Vector; +import java.util.Enumeration; + +import java.awt.Component; +import java.awt.Menu; + +/** + * The common part of the The Javatm Telnet Application + * is handled here. Mainly this includes the loading of the plugins and + * the screen setup of the visual plugins. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class Common extends PluginLoader { + + private Hashtable plugins, components, menus; + + public Common(Properties config) { + System.err.println("** The Java(tm) Telnet Application"); + System.err.println("** Copyright (c) 1996-1999 Matthias L. Jugel, " + +"Marcus Meißner"); + + plugins = new Hashtable(); + components = new Hashtable(); + menus = new Hashtable(); + + Vector names = split(config.getProperty("plugins")); + Enumeration e = names.elements(); + while(e.hasMoreElements()) { + String name = (String)e.nextElement(); + System.err.println("jta: loading plugin '"+name+"' ..."); + Plugin plugin = addPlugin(name); + if(plugin instanceof VisualPlugin) { + Component c = ((VisualPlugin)plugin).getPluginVisual(); + if(c != null) components.put(name, c); + Menu menu = ((VisualPlugin)plugin).getPluginMenu(); + if(menu != null) menus.put(name, menu); + } + } + + broadcast(new ConfigurationRequest(config)); + } + + public Hashtable getComponents() { + return components; + } + + public Hashtable getMenus() { + return menus; + } + + /** + * Split up comma separated lists of strings. This is quite strict, no + * whitespace characters are allowed. + * @param s the string to be split up + * @return an array of strings + */ + private static Vector split(String s) { + Vector v = new Vector(); + int old = -1, idx = s.indexOf(','); + while(idx >= 0) { + v.addElement(s.substring(old + 1, idx)); + old = idx; + idx = s.indexOf(',', old + 1); + } + v.addElement(s.substring(old + 1)); + return v; + } +} blob - /dev/null blob + 418ed0c04e9f06512128d4f146ff8a1f852e2dbb (mode 644) --- /dev/null +++ de/mud/jta/FilterPlugin.java @@ -0,0 +1,57 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta; + +import java.io.IOException; + +/** + * The filter plugin is the base interface for plugins that want to intercept + * the communication between front end and back end plugins. Filters and + * protocol handlers are a good example. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface FilterPlugin { + /** + * Set the source plugin where we get our data from and where the data + * sink (write) is. The actual data handling should be done in the + * read() and write() methods. + * @param source the data source + */ + public void setFilterSource(FilterPlugin source) + throws IllegalArgumentException; + + /** + * Read a block of data from the back end. + * @param b the buffer to read the data into + * @return the amount of bytes actually read + */ + public int read(byte[] b) + throws IOException; + + /** + * Write a block of data to the back end. + * @param b the buffer to be sent + */ + public void write(byte[] b) + throws IOException; +} blob - /dev/null blob + 1ffa2588dc4fd21f04886389031e71be9fa64e3b (mode 644) --- /dev/null +++ de/mud/jta/Main.java @@ -0,0 +1,127 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta; + +import de.mud.jta.event.OnlineStatusListener; +import de.mud.jta.event.SocketRequest; + +import java.util.Properties; +import java.util.Hashtable; +import java.util.Enumeration; + +import java.io.IOException; + +import java.awt.Frame; +import java.awt.Color; +import java.awt.Component; + +/** + * The Java Telnet Application

+ * This is the implementation of whole set of applications. It's modular + * structure allows to configure the software to act either as a sophisticated + * terminal emulation and/or, adding the network backend, as telnet + * implementation. Additional modules provide features like scripting or an + * improved graphical user interface.

+ * This software is written entirely in Javatm.

+ * This is the main program for the command line telnet. It initializes the + * system and adds all needed components, such as the telnet backend and + * the terminal front end. In contrast to applet functionality it parses + * command line arguments used for configuring the software. Additionally + * this application is not restricted in the sense of Javatmp + * security. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class Main extends Frame { + + public static void main(String args[]) { + Properties options = new Properties(); + try { + options.load(options.getClass() + .getResourceAsStream("/de/mud/jta/defaults.opt")); + } catch(IOException e) { + System.err.println("jta: cannot load defaults"); + } + String error = parseOptions(options, args); + if(error != null) { + System.err.println(error); + System.err.println("usage: de.mud.jta.Main [-term id] [host [port]]"); + System.exit(0); + } + + final Frame frame = new Frame("jta: " + +options.getProperty("Socket.host") + +options.getProperty("Socket.port")); + + // configure the application and load all plugins + Common setup = new Common(options); + + setup.registerPluginListener(new OnlineStatusListener() { + public void online() { /* nothing to do */ } + public void offline() { +/* frame.dispose(); + System.exit(0); +*/ } + }); + + Hashtable componentList = setup.getComponents(); + Enumeration names = componentList.keys(); + while(names.hasMoreElements()) { + String name = (String)names.nextElement(); + Component c = (Component)componentList.get(name); + if(options.getProperty("layout."+name) == null) { + System.err.println("jta: no layout property set for '"+name+"'"); + frame.add("South", c); + } else + frame.add(options.getProperty("layout."+name), c); + } + + frame.pack(); + frame.show(); + + setup.broadcast(new SocketRequest(options.getProperty("Socket.host"), + Integer.parseInt(options.getProperty("Socket.port")))); + } + + /** + * Parse the command line argumens and override any standard options + * with the new values if applicable. + *

+ * This method does not work with jdk 1.1.x as the setProperty() + * method is not available. You need to comment this method out + * and replace the class for the old jdk! + * + * @param options the original options + * @param args the command line parameters + * @return a possible error message if problems occur + */ + private static String parseOptions(Properties options, String args[]) { + for(int n = 0; n < args.length; n++) { + if(args[n].equals("-term")) + if(!args[n+1].startsWith("-")) + /* options.setProperty("Terminal.id", args[++n]) */; + else + return "missing parameter for -term"; + } + return null; + } +} blob - /dev/null blob + 35d11b8466bc032fee5cbbdc0b9f0cb2c3f35897 (mode 644) --- /dev/null +++ de/mud/jta/Plugin.java @@ -0,0 +1,42 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta; + +import java.io.IOException; + +/** + * Plugin base class for the Java Telnet Application. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class Plugin { + /** holds the plugin bus used for communication between plugins */ + protected PluginBus bus; + + /** + * Create a new plugin and set the plugin bus used by this plugin. + * @param bus the plugin bus + */ + public Plugin(PluginBus bus) { + this.bus = bus; + } +} blob - /dev/null blob + a2efaff27698bcebb5db824a5ac0cf7473fecf06 (mode 644) --- /dev/null +++ de/mud/jta/PluginBus.java @@ -0,0 +1,38 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta; + +/** + * A plugin bus is used for communication between plugins. The interface + * describes the broadcast method that should broad cast the message + * to all plugins known and return an answer message immediatly.

+ * The functionality is just simuliar to a bus, but depends on the + * actual implementation of the bus. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface PluginBus { + /** Broadcast a plugin message to all listeners. */ + public Object broadcast(PluginMessage message); + /** Register a plugin listener with this bus object */ + public void registerPluginListener(PluginListener listener); +} blob - /dev/null blob + 430e191d5bebc822c8ec6a8719427aabf2ef30d9 (mode 644) --- /dev/null +++ de/mud/jta/PluginListener.java @@ -0,0 +1,30 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta; + +/** + * A tag interface for a plugin message listener. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface PluginListener { +} blob - /dev/null blob + 3084a81a3cda1649e2c0cf0d3c984bc4b7302fe5 (mode 644) --- /dev/null +++ de/mud/jta/PluginLoader.java @@ -0,0 +1,111 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.jta; + +import java.util.Properties; +import java.util.Vector; +import java.util.Enumeration; + +import java.lang.reflect.Constructor; + +/** + * The plugin loader tries to load the plugin by name and returns a + * corresponding plugin object. It takes care of connecting filter + * plugins + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class PluginLoader implements PluginBus { + /** holds the current version id */ + public final static String ID = "$Id$"; + + private final static int debug = 0; + + /** the path to standard plugins */ + private final static String PATH = "de.mud.jta.plugin."; + + /** holds all the filters */ + private Vector filter = new Vector(); + + /** + * Add a new plugin to the system and register the plugin load as its + * communication bus. If the plugin is a filter plugin and if it is + * not the first filter the last added filter will be set as its filter + * source. + * @param name the string name of the plugin + * @return the newly created plugin or null in case of an error + */ + public Plugin addPlugin(String name) { + Plugin plugin = null; + + // load the plugin by name and instantiate it + try { + Class c = Class.forName(PATH+name); + Constructor cc = c.getConstructor(new Class[] { PluginBus.class }); + plugin = (Plugin)cc.newInstance(new Object[] { this }); + } catch(Exception e) { + System.err.println("plugin loader: cannot load "+name); + e.printStackTrace(); + return null; + } + + // configure the filter plugins + if(plugin instanceof FilterPlugin) { + if(filter.size() > 0) + ((FilterPlugin)plugin) + .setFilterSource((FilterPlugin)filter.lastElement()); + filter.addElement(plugin); + } + + return plugin; + } + + /** holds the plugin listener we serve */ + private Vector listener = new Vector(); + + /** + * Register a new plugin listener. + */ + public void registerPluginListener(PluginListener l) { + listener.addElement(l); + } + + /** + * Implementation of the plugin bus. Broadcast a message to all + * listeners we know of. The message takes care that the right + * methods are called in the listeners. + * @param message the plugin message to be sent + * @return the answer to the sent message + */ + public Object broadcast(PluginMessage message) { + if(debug>0) System.err.println("broadcast("+message+")"); + if(message == null || listener == null) + return null; + Enumeration e = listener.elements(); + Object res = null; + while(res == null && e.hasMoreElements()) + res = message.firePluginMessage((PluginListener)e.nextElement()); + return res; + } +} + blob - /dev/null blob + e878d8cce59274a53433983a7451d5c300779748 (mode 644) --- /dev/null +++ de/mud/jta/PluginMessage.java @@ -0,0 +1,37 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta; + +/** + * The base interface for a plugin message. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface PluginMessage { + /** + * Fire the message to all listeners that are compatible with this + * message and return the result. + * @param pl the list of plugin message listeners + * @return the result message + */ + public Object firePluginMessage(PluginListener pl); +} blob - /dev/null blob + 979af0594e61d6b90b55bf2ffe803379806e6895 (mode 644) --- /dev/null +++ de/mud/jta/VisualPlugin.java @@ -0,0 +1,45 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta; + +import java.awt.Component; +import java.awt.Menu; + +/** + * To show data on-screen a plugin may have a visible component. That component + * may either be a single awt component or a container with severel elements. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface VisualPlugin { + /** + * Get the visible components from the plugin. + * @return a component that represents the plugin + */ + public Component getPluginVisual(); + + /** + * Get the menu entry for this component. + * @return a menu that can be used to change the plugin state + */ + public Menu getPluginMenu(); +} blob - /dev/null blob + a06711c2c95d10315bc14c67bfde1d57ee491278 (mode 644) --- /dev/null +++ de/mud/jta/defaults.opt @@ -0,0 +1,52 @@ +# This file is part of "The Java Telnet Application". +# +# This is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# "The Java Telnet Application" 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. +# +# You should have received a copy of the GNU General Public License +# along with this software; see the file COPYING. If not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# ======================================================================= +# common program defaults +# ======================================================================= +plugins = Socket,Telnet,Terminal,Status +layout = BorderLayout +layout.Terminal = Center +layout.Status = South + +# ======================================================================= +# Socket defaults +# ======================================================================= +Socket.host = 10.1.1.1 +Socket.port = 23 + +# ======================================================================= +# Terminal defaults +# ======================================================================= +Terminal.foreground = #000080 +Terminal.background = #a0fff6 +Terminal.border = 0 +Terminal.borderRaised = false +Terminal.borderColor = #a0fff6 +Terminal.colorSet = @/de/mud/terminal/default.colorset +Terminal.scrollBar = West +# now the real configuration +Terminal.id = vt320 +Terminal.buffer = 100 +Terminal.size = [80,24] +Terminal.resize = none +Terminal.font = Courier +Terminal.fontStyle = bold +Terminal.fontSize = 18 +Terminal.keyCodes = @/de/mud/terminal/default.keycodes +Terminal.VMS = false +Terminal.IBM = false blob - /dev/null blob + 2ded6f0459a190c4cbfd3ee9142da911023dd655 (mode 644) --- /dev/null +++ de/mud/jta/event/ConfigurationListener.java @@ -0,0 +1,36 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginListener; + +import java.util.Properties; + +/** + * Configuration listener will be notified of configuration events. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface ConfigurationListener extends PluginListener { + /** Called for configuration changes. */ + public void setConfiguration(Properties config); +} blob - /dev/null blob + dd390d3a48eccea9a0cca23a9171c7e37f919b93 (mode 644) --- /dev/null +++ de/mud/jta/event/ConfigurationRequest.java @@ -0,0 +1,53 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginMessage; +import de.mud.jta.PluginListener; +import de.mud.jta.event.ConfigurationListener; + +import java.util.Properties; + +/** + * Configuration request message. Subclassing this message can be used to + * make the configuration more specific and efficient. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class ConfigurationRequest implements PluginMessage { + Properties config; + + public ConfigurationRequest(Properties config) { + this.config = config; + } + + /** + * Notify all listeners of a configuration event. + * @param pl the list of plugin message listeners + */ + public Object firePluginMessage(PluginListener pl) { + if(pl instanceof ConfigurationListener) { + ((ConfigurationListener)pl).setConfiguration(config); + } + return null; + } +} blob - /dev/null blob + dd22c9a85d0adc75082d4f73f650ed58b343ba1b (mode 644) --- /dev/null +++ de/mud/jta/event/LocalEchoListener.java @@ -0,0 +1,35 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginListener; + +/** + * This interface should be used by plugins who would like to be notified + * about the local echo property. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface LocalEchoListener extends PluginListener { + /** Called if the local echo property changes. */ + public void setLocalEcho(boolean echo); +} blob - /dev/null blob + 63dadb1c5aa4bc8a9a899b961b1e8d1d04965164 (mode 644) --- /dev/null +++ de/mud/jta/event/LocalEchoRequest.java @@ -0,0 +1,52 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginMessage; +import de.mud.jta.PluginListener; +import de.mud.jta.event.LocalEchoListener; + +/** + * Notification of the local echo property. The terminal should echo all + * typed in characters locally of this is true. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class LocalEchoRequest implements PluginMessage { + protected boolean echo; + + /** Create a new local echo request with the specified value. */ + public LocalEchoRequest(boolean echo) { + this.echo = echo; + } + + /** + * Notify all listeners about the status of local echo. + * @param pl the list of plugin message listeners + * @return always null + */ + public Object firePluginMessage(PluginListener pl) { + if(pl instanceof LocalEchoListener) + ((LocalEchoListener)pl).setLocalEcho(echo); + return null; + } +} blob - /dev/null blob + 8da05583f4ecebda6eaa5755d0d521596943105f (mode 644) --- /dev/null +++ de/mud/jta/event/OnlineStatus.java @@ -0,0 +1,53 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginMessage; +import de.mud.jta.PluginListener; + +/** + * Notify all listeners that we on or offline. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class OnlineStatus implements PluginMessage { + protected boolean online; + + /** Create a new online status message with the specified value. */ + public OnlineStatus(boolean online) { + this.online = online; + } + + /** + * Notify the listers about the online status. + * @param pl the list of plugin message listeners + * @return the window size or null + */ + public Object firePluginMessage(PluginListener pl) { + if(pl instanceof OnlineStatusListener) + if(online) + ((OnlineStatusListener)pl).online(); + else + ((OnlineStatusListener)pl).offline(); + return null; + } +} blob - /dev/null blob + a5125bf7234df3e11fb5214ef5d7b7ac64afa1ad (mode 644) --- /dev/null +++ de/mud/jta/event/OnlineStatusListener.java @@ -0,0 +1,38 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginListener; + +import java.awt.Dimension; + +/** + * This is the interface for a online status listener. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface OnlineStatusListener extends PluginListener { + /** Called when the system is online. */ + public void online(); + /** Called when the system is offline. */ + public void offline(); +} blob - /dev/null blob + 856bb296752ffc2bce2839ca8db4374b0e678443 (mode 644) --- /dev/null +++ de/mud/jta/event/SocketListener.java @@ -0,0 +1,42 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginListener; + +import java.net.UnknownHostException; +import java.io.IOException; + +/** + * The socket listener should be implemented by plugins that want to know + * when the whole systems connects or disconnects. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface SocketListener extends PluginListener { + /** Called if a connection should be established. */ + public void connect(String host, int port) + throws UnknownHostException, IOException; + /** Called if the connection should be stopped. */ + public void disconnect() + throws IOException; +} blob - /dev/null blob + d21dc3415ebe488cfaf21d207390f61bc0685dfd (mode 644) --- /dev/null +++ de/mud/jta/event/SocketRequest.java @@ -0,0 +1,65 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginMessage; +import de.mud.jta.PluginListener; +import de.mud.jta.event.SocketListener; + +/** + * Notification of a socket request. Send this message if the system + * should connect or disconnect. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class SocketRequest implements PluginMessage { + String host; + int port; + + /** Create a new disconnect message */ + public SocketRequest() { + host = null; + } + + /** Create a new connect message */ + public SocketRequest(String host, int port) { + this.host = host; + this.port = port; + } + + /** + * Tell all listeners that we would like to connect. + * @param pl the list of plugin message listeners + * @return the terminal type or null + */ + public Object firePluginMessage(PluginListener pl) { + if(pl instanceof SocketListener) try { + if(host != null) + ((SocketListener)pl).connect(host, port); + else + ((SocketListener)pl).disconnect(); + } catch(Exception e) { + e.printStackTrace(); + } + return null; + } +} blob - /dev/null blob + 2be5aea01d0ec57773b6446d5cb63ec2152d6e67 (mode 644) --- /dev/null +++ de/mud/jta/event/TerminalTypeListener.java @@ -0,0 +1,36 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginListener; + +/** + * This is the interface for a terminal type listener. It should return + * the terminal type id as a string. Valid terminal types include + * VT52, VT100, VT200, VT220, VT320, ANSI etc. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface TerminalTypeListener extends PluginListener { + /** Return the terminal type string */ + public String getTerminalType(); +} blob - /dev/null blob + dc2d8cbd1b7d883d5880fbe05ccf88e6e71b6fb4 (mode 644) --- /dev/null +++ de/mud/jta/event/TerminalTypeRequest.java @@ -0,0 +1,47 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginMessage; +import de.mud.jta.PluginListener; +import de.mud.jta.event.TerminalTypeListener; + +/** + * Request message for the current terminal type. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class TerminalTypeRequest implements PluginMessage { + /** + * Ask all terminal type listener about the terminal type and return + * the first answer. + * @param pl the list of plugin message listeners + * @return the terminal type or null + */ + public Object firePluginMessage(PluginListener pl) { + if(pl instanceof TerminalTypeListener) { + Object ret = ((TerminalTypeListener)pl).getTerminalType(); + if(ret != null) return ret; + } + return null; + } +} blob - /dev/null blob + 5a1b866b2bb1a0644e02fd98af2058570ed8aa3b (mode 644) --- /dev/null +++ de/mud/jta/event/WindowSizeListener.java @@ -0,0 +1,36 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginListener; + +import java.awt.Dimension; + +/** + * This is the interface for a window size listener. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public interface WindowSizeListener extends PluginListener { + /** Return the current window size of the terminal in rows and columns. */ + public Dimension getWindowSize(); +} blob - /dev/null blob + a1d991f2e4518857c7665eb7d18a2182a4768bed (mode 644) --- /dev/null +++ de/mud/jta/event/WindowSizeRequest.java @@ -0,0 +1,45 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +package de.mud.jta.event; + +import de.mud.jta.PluginMessage; +import de.mud.jta.PluginListener; +import de.mud.jta.event.WindowSizeListener; + +/** + * Request the current window size of the terminal. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class WindowSizeRequest implements PluginMessage { + /** + * Return the size of the window + * @param pl the list of plugin message listeners + */ + public Object firePluginMessage(PluginListener pl) { + if(pl instanceof WindowSizeListener) { + Object ret = ((WindowSizeListener)pl).getWindowSize(); + if(ret != null) return ret; + } + return null; + } +} blob - /dev/null blob + a20b2ea4a49ceecd7565981ad06fb7fda047fcec (mode 644) --- /dev/null +++ de/mud/jta/plugin/Shell.java @@ -0,0 +1,76 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.jta.plugin; + +import de.mud.jta.Plugin; +import de.mud.jta.FilterPlugin; +import de.mud.jta.PluginBus; +import de.mud.jta.event.LocalEchoRequest; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * The shell plugin is the backend component for terminal emulation using + * a shell. It provides the i/o streams of the shell as data source. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class Shell extends Plugin implements FilterPlugin { + + private final static int debug = 1; + + protected InputStream in, err; + protected OutputStream out; + + public Shell(PluginBus bus) { + super(bus); + Runtime rt = Runtime.getRuntime(); + + try { + Process p = rt.exec("/bin/bash -i"); System.err.println(p); + in = p.getInputStream(); + out = p.getOutputStream(); + err = p.getErrorStream(); + } catch(Exception e) { + e.printStackTrace(); + } + + bus.broadcast(new LocalEchoRequest(true)); + } + + public void setFilterSource(FilterPlugin plugin) { + // we do not have a source other than our socket + } + + public int read(byte[] b) throws IOException { + if(err.available() > 0) return err.read(b); + return in.read(b); + } + + public void write(byte[] b) throws IOException { + out.write(b); + out.flush(); + } +} blob - /dev/null blob + bde73e12b93315bdf2e1597d748230a04dd7d15e (mode 644) --- /dev/null +++ de/mud/jta/plugin/Socket.java @@ -0,0 +1,89 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.jta.plugin; + +import de.mud.jta.Plugin; +import de.mud.jta.FilterPlugin; +import de.mud.jta.PluginBus; +import de.mud.jta.event.SocketListener; +import de.mud.jta.event.OnlineStatus; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.net.UnknownHostException; + +/** + * The socket plugin acts as the data source for networked operations. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class Socket extends Plugin implements FilterPlugin, SocketListener { + + private final static int debug = 0; + protected java.net.Socket socket; + protected InputStream in; + protected OutputStream out; + + /** + * Create a new socket plugin. + */ + public Socket(PluginBus pbus) { + super(pbus); + final PluginBus bus = pbus; + + // register socket listener + bus.registerPluginListener(this); + } + + /** Connect to the host and port passed. */ + public void connect(String host, int port) + throws UnknownHostException, IOException { + if(debug>0) System.err.println("Socket: connect("+host+","+port+")"); + socket = new java.net.Socket(host, port); + in = socket.getInputStream(); + out = socket.getOutputStream(); + bus.broadcast(new OnlineStatus(true)); + } + + /** Disconnect the socket and close the connection. */ + public void disconnect() throws IOException { + if(debug>0) System.err.println("Socket: disconnect()"); + bus.broadcast(new OnlineStatus(false)); + socket.close(); + } + + public void setFilterSource(FilterPlugin plugin) { + // we do not have a source other than our socket + } + + public int read(byte[] b) throws IOException { + int n = in.read(b); + if(n < 0) disconnect(); + return n; + } + + public void write(byte[] b) throws IOException { + out.write(b); + } +} blob - /dev/null blob + 48e9f00eb584bc57cf24da9cfdff27547b5c6156 (mode 644) --- /dev/null +++ de/mud/jta/plugin/Status.java @@ -0,0 +1,69 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.jta.plugin; + +import de.mud.jta.Plugin; +import de.mud.jta.PluginBus; +import de.mud.jta.VisualPlugin; +import de.mud.jta.event.OnlineStatusListener; + +import java.awt.Component; +import java.awt.Menu; +import java.awt.Label; +import java.awt.Color; + +/** + * A simple plugin showing the current status of the application whether + * it is online or not. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class Status extends Plugin implements VisualPlugin { + + private final static int debug = 1; + + private Label status; + + public Status(PluginBus bus) { + super(bus); + status = new Label("offline", Label.RIGHT); + bus.registerPluginListener(new OnlineStatusListener() { + public void online() { + status.setText("online"); + status.setBackground(Color.green); + } + public void offline() { + status.setText("offline"); + status.setBackground(Color.red); + } + }); + } + + public Component getPluginVisual() { + return status; + } + + public Menu getPluginMenu() { + return null; + } +} blob - /dev/null blob + 61aa353cc35440bb5a71404113eb8923830e8e63 (mode 644) --- /dev/null +++ de/mud/jta/plugin/Telnet.java @@ -0,0 +1,94 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.jta.plugin; + +import de.mud.jta.Plugin; +import de.mud.jta.FilterPlugin; +import de.mud.jta.PluginBus; + +import de.mud.jta.event.TerminalTypeRequest; +import de.mud.jta.event.WindowSizeRequest; +import de.mud.jta.event.LocalEchoRequest; + +import de.mud.telnet.TelnetProtocolHandler; + +import java.awt.Dimension; + +import java.io.IOException; + +/** + * The telnet plugin utilizes a telnet protocol handler to filter + * telnet negotiation requests from the data stream. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class Telnet extends Plugin implements FilterPlugin { + + protected FilterPlugin source; + protected TelnetProtocolHandler handler; + + private final static int debug = 0; + + /** + * Create a new telnet plugin. + */ + public Telnet(PluginBus pbus) { + super(pbus); + final PluginBus bus = pbus; + + // create a new telnet protocol handler + handler = new TelnetProtocolHandler() { + /** get the current terminal type */ + public String getTerminalType() { + return (String)bus.broadcast(new TerminalTypeRequest()); + } + /** get the current window size */ + public Dimension getWindowSize() { + return (Dimension)bus.broadcast(new WindowSizeRequest()); + } + /** notify about local echo */ + public void setLocalEcho(boolean echo) { + bus.broadcast(new LocalEchoRequest(echo)); + } + /** write data to our back end */ + public void write(byte[] b) throws IOException { + source.write(b); + } + }; + } + + public void setFilterSource(FilterPlugin source) { + if(debug>0) System.err.println("Telnet: connected to: "+source); + this.source = source; + } + + public int read(byte[] b) throws IOException { + int n = source.read(b); + if(n > 0) n = handler.negotiate(b, n); + return n; + } + + public void write(byte[] b) throws IOException { + source.write(b); + } +} blob - /dev/null blob + d4bc46654fc3165ebb188932cdde2c68bcc50b89 (mode 644) --- /dev/null +++ de/mud/jta/plugin/Terminal.java @@ -0,0 +1,226 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.jta.plugin; + +import de.mud.jta.Plugin; +import de.mud.jta.FilterPlugin; +import de.mud.jta.VisualPlugin; +import de.mud.jta.PluginBus; + +import de.mud.terminal.vt320; + +import de.mud.jta.event.ConfigurationListener; +import de.mud.jta.event.OnlineStatusListener; +import de.mud.jta.event.TerminalTypeListener; +import de.mud.jta.event.WindowSizeListener; +import de.mud.jta.event.LocalEchoListener; + +import java.awt.Component; +import java.awt.Menu; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Color; + +import java.io.IOException; + +import java.util.Properties; +import java.util.Enumeration; + +/** + * The terminal plugin represents the actual terminal where the + * data will be displayed and the gets the keyboard input to sent + * back to the remote host, + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class Terminal extends Plugin + implements FilterPlugin, VisualPlugin, Runnable { + + private final static int debug = 0; + + /** holds the actual terminal emulation */ + protected vt320 terminal; + + private Thread reader = null; + + /** + * Create a new terminal plugin and initialize the terminal emulation. + */ + public Terminal(PluginBus bus) { + super(bus); + terminal = new vt320() { + public void write(byte[] b) { + try { + Terminal.this.write(b); + } catch(IOException e) { + reader = null; + } + } + }; + + // register an online status listener + bus.registerPluginListener(new OnlineStatusListener() { + public void online() { + if(debug > 0) System.err.println("Terminal: online"); + if(reader == null) { + reader = new Thread(Terminal.this); + reader.start(); + } + } + + public void offline() { + if(debug > 0) System.err.println("Terminal: offline"); + if(reader != null) + reader = null; + } + }); + + bus.registerPluginListener(new TerminalTypeListener() { + public String getTerminalType() { + return terminal.getTerminalID(); + } + }); + + bus.registerPluginListener(new WindowSizeListener() { + public Dimension getWindowSize() { + return terminal.getScreenSize(); + } + }); + + bus.registerPluginListener(new LocalEchoListener() { + public void setLocalEcho(boolean echo) { + terminal.setLocalEcho(echo); + } + }); + + bus.registerPluginListener(new ConfigurationListener() { + public void setConfiguration(Properties config) { + configure(config); + } + }); + } + + private void configure(Properties config) { + Enumeration p = config.keys(); + + while(p.hasMoreElements()) { + String key = (String)p.nextElement(); + if(key.startsWith("Terminal.")) { + if(key.equals("Terminal.foreground")) + terminal.setForeground(Color.decode(config.getProperty(key))); + else if(key.equals("Terminal.background")) + terminal.setBackground(Color.decode(config.getProperty(key))); + else if(key.equals("Terminal.colorSet")) + System.err.println("Terminal.colorSet not implemented yet"); + else if(key.equals("Terminal.borderRaised")) + /* do nothing */ ; + else if(key.equals("Terminal.border")) { + boolean raised = false; + if(config.contains("Terminal.borderStyle")) + raised = Boolean.getBoolean("Terminal.borderRaised"); + terminal.setBorder(Integer.parseInt(config.getProperty(key)), + raised); + } else if(key.equals("Terminal.borderColor")) + terminal.setBackground(Color.decode(config.getProperty(key))); + else if(key.equals("Terminal.scrollBar")) + System.err.println("Terminal.scrollBar not implemented yet"); + else if(key.equals("Terminal.id")) + terminal.setTerminalID(config.getProperty(key)); + else if(key.equals("Terminal.buffer")) + terminal.setBufferSize(Integer.parseInt(config.getProperty(key))); + else if(key.equals("Terminal.size")) + System.err.println("Terminal.size not implemented yet"); + else if(key.equals("Terminal.resize")) { + String resize = config.getProperty("Terminal.resize"); + if(resize.equals("font")) + terminal.setResizeStrategy(terminal.RESIZE_FONT); + else if(resize.equals("screen")) + terminal.setResizeStrategy(terminal.RESIZE_SCREEN); + else + terminal.setResizeStrategy(terminal.RESIZE_NONE); + } else if(key.equals("Terminal.fontSize") || + key.equals("Terminal.fontStyle")) + /* do nothing */ ; + else if(key.equals("Terminal.font")) { + int style = Font.PLAIN, fsize = 12; + if(config.containsKey("Terminal.fontSize")) + fsize = Integer.parseInt(config.getProperty("Terminal.fontSize")); + String fontStyle = config.getProperty("Terminal.fontStyle"); + if(fontStyle == null || fontStyle.equals("plain")) + style = Font.PLAIN; + else if(fontStyle.equals("bold")) + style = Font.BOLD; + else if(fontStyle.equals("italic")) + style = Font.ITALIC; + System.err.println(new Font(config.getProperty(key), style, fsize)); + terminal.setFont(new Font(config.getProperty(key), style, fsize)); + } else if(key.equals("Terminal.keyCodes")) + System.err.println("Terminal.keyCodes not implemented yet"); + else if(key.equals("Terminal.VMS")) + terminal.setVMS(Boolean.getBoolean(config.getProperty(key))); + else if(key.equals("Terminal.IBM")) + terminal.setIBMCharset(Boolean.getBoolean(config.getProperty(key))); + else + System.err.println("Error: '"+key+"' is not a Terminal property"); + } + } + } + + /** + * Continuously read from our back end and display the data on screen. + */ + public void run() { + byte[] t, b = new byte[256]; + int n = 0; + while(n >= 0) try { + n = read(b); + if(n > 0) terminal.putString(new String(b, 0, n)); + } catch(IOException e) { + reader = null; + return; + } + } + + protected FilterPlugin source; + + public void setFilterSource(FilterPlugin source) { + if(debug > 0) System.err.println("Terminal: connected to: "+source); + this.source = source; + } + + public int read(byte[] b) throws IOException { + return source.read(b); + } + + public void write(byte[] b) throws IOException { + source.write(b); + } + + public Component getPluginVisual() { + return terminal; + } + + public Menu getPluginMenu() { + return null; + } +} blob - /dev/null blob + a28236e63498f21f2d5ae26e722d0210006f450d (mode 644) --- /dev/null +++ de/mud/telnet/TelnetProtocolHandler.java @@ -0,0 +1,457 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.telnet; + +import java.io.IOException; +import java.awt.Dimension; + +/** + * This is a telnet protocol handler. The handler needs implementations + * for several methods to handle the telnet options and to be able to + * read and write the buffer. + *

+ * Maintainer: Marcus Meißner + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public abstract class TelnetProtocolHandler { + /** contains the current revision id */ + public final static String ID = "$Id$"; + + /** debug level */ + private final static int debug = 0; + + /** + * Create a new telnet protocol handler. + */ + public TelnetProtocolHandler() { + reset(); + } + + /** + * Get the current terminal type for TTYPE telnet option. + * @return the string id of the terminal + */ + protected abstract String getTerminalType(); + + /** + * Get the current window size of the terminal for the + * NAWS telnet option. + * @return the size of the terminal as Dimension + */ + protected abstract Dimension getWindowSize(); + + /** + * Set the local echo option of telnet. + * @param echo true for local echo, false for no local echo + */ + protected abstract void setLocalEcho(boolean echo); + + /** + * Send data to the remote host. + * @param b array of bytes to send + */ + protected abstract void write(byte[] b) throws IOException; + + /** + * Send one byte to the remote host. + * @param b the byte to be sent + * @see #write(byte[] b) + */ + private static byte[] one = new byte[1]; + private void write(byte b) throws IOException { + one[0] = b; + write(one); + } + + /** + * Reset the protocol handler. This may be necessary after the + * connection was closed or some other problem occured. + */ + public void reset() { + neg_state = 0; + receivedDX = new byte[256]; + sentDX = new byte[256]; + receivedWX = new byte[256]; + sentWX = new byte[256]; + } + + // =================================================================== + // the actual negotiation handling for the telnet protocol follows: + // =================================================================== + + /** state variable for telnet negotiation reader */ + private byte neg_state = 0; + + /** constants for the negotiation state */ + private final static byte STATE_DATA = 0; + private final static byte STATE_IAC = 1; + private final static byte STATE_IACSB = 2; + private final static byte STATE_IACWILL = 3; + private final static byte STATE_IACDO = 4; + private final static byte STATE_IACWONT = 5; + private final static byte STATE_IACDONT = 6; + private final static byte STATE_IACSBIAC = 7; + private final static byte STATE_IACSBDATA = 8; + private final static byte STATE_IACSBDATAIAC = 9; + + /** What IAC SB we are handling right now */ + private byte current_sb; + + /** IAC - init sequence for telnet negotiation. */ + private final static byte IAC = (byte)255; + /** [IAC] End Of Record */ + private final static byte EOR = (byte)239; + /** [IAC] WILL */ + private final static byte WILL = (byte)251; + /** [IAC] WONT */ + private final static byte WONT = (byte)252; + /** [IAC] DO */ + private final static byte DO = (byte)253; + /** [IAC] DONT */ + private final static byte DONT = (byte)254; + /** [IAC] Sub Begin */ + private final static byte SB = (byte)250; + /** [IAC] Sub End */ + private final static byte SE = (byte)240; + /** Telnet option: echo text */ + private final static byte TELOPT_ECHO = (byte)1; /* echo on/off */ + /** Telnet option: End Of Record */ + private final static byte TELOPT_EOR = (byte)25; /* end of record */ + /** Telnet option: Negotiate About Window Size */ + private final static byte TELOPT_NAWS = (byte)31; /* NA-WindowSize*/ + /** Telnet option: Terminal Type */ + private final static byte TELOPT_TTYPE = (byte)24; /* terminal type */ + + private final static byte[] IACWILL = { IAC, WILL }; + private final static byte[] IACWONT = { IAC, WONT }; + private final static byte[] IACDO = { IAC, DO }; + private final static byte[] IACDONT = { IAC, DONT }; + private final static byte[] IACSB = { IAC, SB }; + private final static byte[] IACSE = { IAC, SE }; + + /** Telnet option qualifier 'IS' */ + private final static byte TELQUAL_IS = (byte)0; + /** Telnet option qualifier 'SEND' */ + private final static byte TELQUAL_SEND = (byte)1; + + /** What IAC DO(NT) request do we have received already ? */ + private byte[] receivedDX; + /** What IAC WILL/WONT request do we have received already ? */ + private byte[] receivedWX; + /** What IAC DO/DONT request do we have sent already ? */ + private byte[] sentDX; + /** What IAC WILL/WONT request do we have sent already ? */ + private byte[] sentWX; + + /** + * Handle an incoming IAC SB <type> <bytes> IAC SE + * @param type type of SB + * @param sbata byte array as <bytes> + * @param sbcount nr of bytes. may be 0 too. + */ + private void handle_sb(byte type, byte[] sbdata, int sbcount) + throws IOException { + if(debug > 1) + System.err.println("TelnetIO.handle_sb("+type+")"); + switch (type) { + case TELOPT_TTYPE: + if (sbcount>0 && sbdata[0]==TELQUAL_SEND) { + write(IACSB);write(TELOPT_TTYPE);write(TELQUAL_IS); + /* FIXME: need more logic here if we use + * more than one terminal type + */ + String ttype = getTerminalType(); + if(ttype == null) ttype = "dumb"; + write(ttype.getBytes()); + write(IACSE); + } + + } + } + + /** + * Handle telnet protocol negotiation. The buffer will be parsed + * and necessary actions are taken according to the telnet protocol. + * See RFC-Telnet + * @param buf the byte buffer used for negotiation + * @param count the amount of bytes in the buffer + * @return a new buffer after negotiation + */ + public int negotiate(byte buf[], int count) throws IOException { + // wo faengt buf an bei buf[0] oder bei buf[1] + // Leo: bei buf[0] + if(debug > 1) + System.err.println("TelnetIO.negotiate("+buf+","+count+")"); + byte nbuf[] = new byte[count]; + byte sbbuf[] = new byte[count]; + byte sendbuf[] = new byte[3]; + byte b,reply; + int sbcount = 0; + int boffset = 0, noffset = 0; + + while(boffset < count) { + b=buf[boffset++]; + // of course, byte is a signed entity (-128 -> 127) + // but apparently the SGI Netscape 3.0 doesn't seem + // to care and provides happily values up to 255 + if (b>=128) + b=(byte)((int)b-256); + switch (neg_state) { + case STATE_DATA: + if (b==IAC) + neg_state = STATE_IAC; + else + nbuf[noffset++]=b; + break; + case STATE_IAC: + switch (b) { + case IAC: + if(debug > 2) System.err.print("IAC "); + neg_state = STATE_DATA; + nbuf[noffset++]=IAC; + break; + case WILL: + if(debug > 2) System.err.print("WILL "); + neg_state = STATE_IACWILL; + break; + case WONT: + if(debug > 2) System.err.print("WONT "); + neg_state = STATE_IACWONT; + break; + case DONT: + if(debug > 2) System.err.print("DONT "); + neg_state = STATE_IACDONT; + break; + case DO: + if(debug > 2) System.err.print("DO "); + neg_state = STATE_IACDO; + break; + case EOR: + if(debug > 2) System.err.print("EOR "); + neg_state = STATE_DATA; + break; + case SB: + if(debug > 2) System.err.print("SB "); + neg_state = STATE_IACSB; + sbcount = 0; + break; + default: + if(debug > 2) System.err.print(" "); + neg_state = STATE_DATA; + break; + } + break; + case STATE_IACWILL: + switch(b) { + case TELOPT_ECHO: + if(debug > 2) System.err.println("ECHO"); + reply = DO; + setLocalEcho(false); + break; + case TELOPT_EOR: + if(debug > 2) System.err.println("EOR"); + reply = DO; + break; + default: + if(debug > 2) System.err.println(""); + reply = DONT; + break; + } + if(debug > 1) System.err.println("<"+b+", WILL ="+WILL+">"); + if (reply != sentDX[b+128] || WILL != receivedWX[b+128]) { + sendbuf[0]=IAC; + sendbuf[1]=reply; + sendbuf[2]=b; + write(sendbuf); + sentDX[b+128] = reply; + receivedWX[b+128] = WILL; + } + neg_state = STATE_DATA; + break; + case STATE_IACWONT: + switch(b) { + case TELOPT_ECHO: + if(debug > 2) System.err.println("ECHO"); + setLocalEcho(true); + reply = DONT; + break; + case TELOPT_EOR: + if(debug > 2) System.err.println("EOR"); + reply = DONT; + break; + default: + if(debug > 2) System.err.println(""); + reply = DONT; + break; + } + if(reply != sentDX[b+128] || WONT != receivedWX[b+128]) { + sendbuf[0]=IAC; + sendbuf[1]=reply; + sendbuf[2]=b; + write(sendbuf); + sentDX[b+128] = reply; + receivedWX[b+128] = WILL; + } + neg_state = STATE_DATA; + break; + case STATE_IACDO: + switch (b) { + case TELOPT_ECHO: + if(debug > 2) System.err.println("ECHO"); + reply = WILL; + setLocalEcho(true); + break; + case TELOPT_TTYPE: + if(debug > 2) System.err.println("TTYPE"); + reply = WILL; + break; + case TELOPT_NAWS: + if(debug > 2) System.err.println("NAWS"); + Dimension size = getWindowSize(); + receivedDX[b] = DO; + if(size == null) { + // this shouldn't happen + write(IAC); + write(WONT); + write(TELOPT_NAWS); + reply = WONT; + sentWX[b] = WONT; + break; + } + reply = WILL; + sentWX[b] = WILL; + sendbuf[0]=IAC; + sendbuf[1]=WILL; + sendbuf[2]=TELOPT_NAWS; + write(sendbuf); + write(IAC);write(SB);write(TELOPT_NAWS); + write((byte) (size.width >> 8)); + write((byte) (size.width & 0xff)); + write((byte) (size.height >> 8)); + write((byte) (size.height & 0xff)); + write(IAC);write(SE); + break; + default: + if(debug > 2) System.err.println(""); + reply = WONT; + break; + } + if(reply != sentWX[128+b] || DO != receivedDX[128+b]) { + sendbuf[0]=IAC; + sendbuf[1]=reply; + sendbuf[2]=b; + write(sendbuf); + sentWX[b+128] = reply; + receivedDX[b+128] = DO; + } + neg_state = STATE_DATA; + break; + case STATE_IACDONT: + switch (b) { + case TELOPT_ECHO: + if(debug > 2) System.err.println("ECHO"); + reply = WONT; + setLocalEcho(false); + break; + case TELOPT_NAWS: + if(debug > 2) System.err.println("NAWS"); + reply = WONT; + break; + default: + if(debug > 2) System.err.println(""); + reply = WONT; + break; + } + if(reply != sentWX[b+128] || DONT != receivedDX[b+128]) { + write(IAC);write(reply);write(b); + sentWX[b+128] = reply; + receivedDX[b+128] = DONT; + } + neg_state = STATE_DATA; + break; + case STATE_IACSBIAC: + if(debug > 2) System.err.println(""+b+" "); + if (b == IAC) { + sbcount = 0; + current_sb = b; + neg_state = STATE_IACSBDATA; + } else { + System.err.println("(bad) "+b+" "); + neg_state = STATE_DATA; + } + break; + case STATE_IACSB: + if(debug > 2) System.err.println(""+b+" "); + switch (b) { + case IAC: + neg_state = STATE_IACSBIAC; + break; + default: + current_sb = b; + sbcount = 0; + neg_state = STATE_IACSBDATA; + break; + } + break; + case STATE_IACSBDATA: + if (debug > 2) System.err.println(""+b+" "); + switch (b) { + case IAC: + neg_state = STATE_IACSBDATAIAC; + break; + default: + sbbuf[sbcount++] = b; + break; + } + break; + case STATE_IACSBDATAIAC: + if (debug > 2) System.err.println(""+b+" "); + switch (b) { + case IAC: + neg_state = STATE_IACSBDATA; + sbbuf[sbcount++] = IAC; + break; + case SE: + handle_sb(current_sb,sbbuf,sbcount); + current_sb = 0; + neg_state = STATE_DATA; + break; + case SB: + handle_sb(current_sb,sbbuf,sbcount); + neg_state = STATE_IACSB; + break; + default: + neg_state = STATE_DATA; + break; + } + break; + default: + if (debug > 2) + System.err.println("This should not happen: "+neg_state+" "); + neg_state = STATE_DATA; + break; + } + } + System.arraycopy(nbuf, 0, buf, 0, noffset); + return noffset; + } +} blob - /dev/null blob + 53d4cdc95f2c62d72298b476293c3bf00e6c47b5 (mode 644) --- /dev/null +++ de/mud/terminal/SoftFont.java @@ -0,0 +1,1006 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.terminal; + +import java.awt.*; +import java.util.*; + +/** + * Any characters that are not available in standard java fonts may be + * drawn using the softfont utility. This utility class was derived from + * the cpi fonts used in linux console drivers.

+ * Font file generated by cpi2fnt + *

+ * Maintainer: Marcus Meißner + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class SoftFont { + final static private char SF_BITMAP = 0; + final static private char SF_FILLRECT = 1; + + + final static private char SF_CHAR = 0; + final static private char SF_WIDTH= 1; + final static private char SF_HEIGHT= 2; + final static private char SF_TYPE = 3; + final static private char SF_DATA = 4; + java.util.Hashtable font; + /** softfont characterdata */ + private static char[][] fontdata = { + + {0x01,8,8,SF_BITMAP, /* 1 0x01 '^A' */ + 0x7e, /* 01111110 */ + 0x81, /* 10000001 */ + 0xa5, /* 10100101 */ + 0x81, /* 10000001 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0x81, /* 10000001 */ + 0x7e, /* 01111110 */ + },{ 0x02,8,8,SF_BITMAP,/* 2 0x02 '^B' */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xdb, /* 11011011 */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + },{ 0x03,8,8,SF_BITMAP,/* 3 0x03 '^C' */ + 0x6c, /* 01101100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + },{ 0x04,8,8,SF_BITMAP,/* 4 0x04 '^D' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + },{ 0x05,8,8,SF_BITMAP,/* 5 0x05 '^E' */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0x38, /* 00111000 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0xd6, /* 11010110 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + },{ 0x06,8,8,SF_BITMAP,/* 6 0x06 '^F' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7c, /* 01111100 */ + 0xfe, /* 11111110 */ + 0xfe, /* 11111110 */ + 0x7c, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + },{ 0x2666,8,8,SF_BITMAP,/* 9830 0x2666 BLACK DIAMOND */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x07,8,8,SF_BITMAP,/* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x08,8,8,SF_BITMAP,/* 8 0x08 '^H' */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0xe7, /* 11100111 */ + 0xc3, /* 11000011 */ + 0xc3, /* 11000011 */ + 0xe7, /* 11100111 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + },{ 0x09,8,8,SF_BITMAP,/* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x42, /* 01000010 */ + 0x42, /* 01000010 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + },{ 0x0a,8,8,SF_BITMAP,/* 10 0x0a '^J' */ + 0xff, /* 11111111 */ + 0xc3, /* 11000011 */ + 0x99, /* 10011001 */ + 0xbd, /* 10111101 */ + 0xbd, /* 10111101 */ + 0x99, /* 10011001 */ + 0xc3, /* 11000011 */ + 0xff, /* 11111111 */ + },{ 0x0b,8,8,SF_BITMAP,/* 11 0x0b '^K' */ + 0x0f, /* 00001111 */ + 0x07, /* 00000111 */ + 0x0f, /* 00001111 */ + 0x7d, /* 01111101 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0xcc, /* 11001100 */ + 0x78, /* 01111000 */ + },{ 0x0c,8,8,SF_BITMAP,/* 12 0x0c '^L' */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + },{ 0x0d,8,8,SF_BITMAP,/* 13 0x0d '^M' */ + 0x3f, /* 00111111 */ + 0x33, /* 00110011 */ + 0x3f, /* 00111111 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x70, /* 01110000 */ + 0xf0, /* 11110000 */ + 0xe0, /* 11100000 */ + },{ 0x0e,8,8,SF_BITMAP,/* 14 0x0e '^N' */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x7f, /* 01111111 */ + 0x63, /* 01100011 */ + 0x63, /* 01100011 */ + 0x67, /* 01100111 */ + 0xe6, /* 11100110 */ + 0xc0, /* 11000000 */ + },{ 0x0f,8,8,SF_BITMAP,/* 15 0x0f '^O' */ + 0x18, /* 00011000 */ + 0xdb, /* 11011011 */ + 0x3c, /* 00111100 */ + 0xe7, /* 11100111 */ + 0xe7, /* 11100111 */ + 0x3c, /* 00111100 */ + 0xdb, /* 11011011 */ + 0x18, /* 00011000 */ + },{ 0x10,8,8,SF_BITMAP,/* 16 0x10 '^P' */ + 0x80, /* 10000000 */ + 0xe0, /* 11100000 */ + 0xf8, /* 11111000 */ + 0xfe, /* 11111110 */ + 0xf8, /* 11111000 */ + 0xe0, /* 11100000 */ + 0x80, /* 10000000 */ + 0x00, /* 00000000 */ + },{ 0x11,8,8,SF_BITMAP,/* 17 0x11 '^Q' */ + 0x02, /* 00000010 */ + 0x0e, /* 00001110 */ + 0x3e, /* 00111110 */ + 0xfe, /* 11111110 */ + 0x3e, /* 00111110 */ + 0x0e, /* 00001110 */ + 0x02, /* 00000010 */ + 0x00, /* 00000000 */ + },{ 0x12,8,8,SF_BITMAP,/* 18 0x12 '^R' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + },{ 0x13,8,8,SF_BITMAP,/* 19 0x13 '^S' */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + },{ 0x14,8,8,SF_BITMAP,/* 20 0x14 '^T' */ + 0x7f, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0x7b, /* 01111011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x00, /* 00000000 */ + },{ 0x15,8,8,SF_BITMAP,/* 21 0x15 '^U' */ + 0x3e, /* 00111110 */ + 0x61, /* 01100001 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x86, /* 10000110 */ + 0x7c, /* 01111100 */ + },{ 0x16,8,8,SF_BITMAP,/* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + },{ 0x17,8,8,SF_BITMAP,/* 23 0x17 '^W' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0xff, /* 11111111 */ + },{ 0x18,8,8,SF_BITMAP,/* 24 0x18 '^X' */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + },{ 0x19,8,8,SF_BITMAP,/* 25 0x19 '^Y' */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + },{ 0x1a,8,8,SF_BITMAP,/* 26 0x1a '^Z' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00001100 */ + 0xfe, /* 11111110 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1b,8,8,SF_BITMAP,/* 27 0x1b '^[' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x60, /* 01100000 */ + 0xfe, /* 11111110 */ + 0x60, /* 01100000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1c,8,8,SF_BITMAP,/* 28 0x1c '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xc0, /* 11000000 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1d,8,8,SF_BITMAP,/* 29 0x1d '^]' */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x66, /* 01100110 */ + 0xff, /* 11111111 */ + 0x66, /* 01100110 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1e,8,8,SF_BITMAP,/* 30 0x1e '^^' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x7e, /* 01111110 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x1f,8,8,SF_BITMAP,/* 31 0x1f '^_' */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + 0xff, /* 11111111 */ + 0x7e, /* 01111110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x7f,8,8,SF_BITMAP,/* 127 0x7f '' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x6c, /* 01101100 */ + 0xc6, /* 11000110 */ + 0xc6, /* 11000110 */ + 0xfe, /* 11111110 */ + 0x00, /* 00000000 */ + },{ 0x2591,8,8,SF_BITMAP,/* LIGHT SHADE */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + 0x22, /* 00100010 */ + 0x88, /* 10001000 */ + },{ 0x2592,8,8,SF_BITMAP,/* MEDIUM SHADE */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + 0x55, /* 01010101 */ + 0xaa, /* 10101010 */ + },{ 0x2593,8,8,SF_BITMAP,/* DARK SHADE */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + 0x77, /* 01110111 */ + 0xdd, /* 11011101 */ + },{ 0x221a,8,8,SF_BITMAP,/* SQUARE ROOT */ + 0x78, /* 01111000 */ + 0x0c, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00110000 */ + 0x7c, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + },{ 0x2320,8,8,SF_BITMAP,/* UPPER INTERVAL*/ + 0x0e, /* 00001110 */ + 0x1b, /* 00011011 */ + 0x1b, /* 00011011 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + },{ 0x25a0,8,8,SF_FILLRECT,/* BLACK SQUARE */ + 0x2244, + /* 00000000 */ + /* 00000000 */ + /* 00111100 */ + /* 00111100 */ + /* 00111100 */ + /* 00111100 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2502,8,8,SF_FILLRECT,/*BOX DRAWINGS LIGHT VERTICAL*/ + 0x3028, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2524,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + 0x3028, + 0x0431, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2561,8,8,SF_FILLRECT,/*BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE*/ + 0x3028, + 0x0231, + 0x0431, + /* 00011000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2562,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE */ + 0x2028, + 0x5028, + 0x0421, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 11110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2556,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE */ + 0x0471, + 0x2523, + 0x5523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2555,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE */ + 0x3226, + 0x0231, + 0x0431, + /* 00000000 */ + /* 00000000 */ + /* 11111000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2563,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND LEFT*/ + 0x2022, + 0x0221, + 0x0421, + 0x2424, + 0x5028, + /* 00110110 */ + /* 00110110 */ + /* 11110110 */ + /* 00000110 */ + /* 11110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2551,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL */ + 0x2028, + 0x5028, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2557,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND LEFT */ + 0x0271, + 0x5325, + 0x0441, + 0x2523, + /* 00000000 */ + /* 00000000 */ + /* 11111110 */ + /* 00000110 */ + /* 11110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x255d,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND LEFT */ + 0x2022, + 0x0241, + 0x5025, + 0x0451, + /* 00110110 */ + /* 00110110 */ + /* 11110110 */ + /* 00000110 */ + /* 11111110 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x255c,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND LEFT SINGLE */ + 0x2024, + 0x5024, + 0x0471, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 11111110 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x255b,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND LEFT DOUBLE */ + 0x3025, + 0x0231, + 0x0431, + /* 00011000 */ + /* 00011000 */ + /* 11111000 */ + /* 00011000 */ + /* 11111000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2510,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND LEFT */ + 0x0451, + 0x3523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2514,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND RIGHT */ + 0x3025, + 0x5431, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2534,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + 0x3024, + 0x0481, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x252c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + 0x0481, + 0x3523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x251c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + 0x3028, + 0x5431, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2500,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT HORIZONTAL */ + 0x0481, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x253c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + 0x3028, + 0x0481, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 11111111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x255e,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE */ + 0x3028, + 0x5231, + 0x5431, + /* 00011000 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x255f,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE */ + 0x2028, + 0x5028, + 0x7411, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x255a,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND RIGHT */ + 0x2025, + 0x5023, + 0x7211, + 0x4441, + /* 00110110 */ + /* 00110110 */ + /* 00110111 */ + /* 00110000 */ + /* 00111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2554,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND RIGHT */ + 0x2261, + 0x2325, + 0x5424, + 0x7411, + /* 00000000 */ + /* 00000000 */ + /* 00111111 */ + /* 00110000 */ + /* 00110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2569,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE UP AND HORIZONTAL */ + 0x2022, + 0x0241, + 0x5022, + 0x5231, + 0x0481, + /* 00110110 */ + /* 00110110 */ + /* 11110111 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2566,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL */ + 0x0281, + 0x0441, + 0x2523, + 0x5431, + 0x5523, + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 11110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2560,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND RIGHT */ + 0x2028, + 0x5022, + 0x5231, + 0x5431, + 0x5623, + /* 00110110 */ + /* 00110110 */ + /* 00110111 */ + /* 00110000 */ + /* 00110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2550,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE HORIZONTAL */ + 0x0281, + 0x0481, + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x256c,8,8,SF_FILLRECT,/* BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL */ + 0x2022, + 0x0241, + 0x5022, + 0x5231, + 0x0441, + 0x2523, + 0x5431, + 0x5523, + /* 00110110 */ + /* 00110110 */ + /* 11110111 */ + /* 00000000 */ + /* 11110111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2567,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE */ + 0x3022, + 0x0281, + 0x0481, + /* 00011000 */ + /* 00011000 */ + /* 11111111 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2568,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE */ + 0x2024, + 0x5024, + 0x0481, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2564,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE */ + 0x0281, + 0x0481, + 0x3523, + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00000000 */ + /* 11111111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2565,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE */ + 0x0481, + 0x2523, + 0x5523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x2559,8,8,SF_FILLRECT,/* BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE */ + 0x2024, + 0x5024, + 0x2461, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2558,8,8,SF_FILLRECT,/* BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE */ + 0x3025, + 0x5231, + 0x5431, + /* 00011000 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x2552,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE */ + 0x3226, + 0x5231, + 0x5431, + /* 00000000 */ + /* 00000000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2553,8,8,SF_FILLRECT,/* BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE */ + 0x2461, + 0x2523, + 0x5523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00111111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x256b,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE */ + 0x2028, + 0x5028, + 0x0481, + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + /* 11111111 */ + /* 00110110 */ + /* 00110110 */ + /* 00110110 */ + },{ 0x256a,8,8,SF_FILLRECT,/* BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE */ + 0x3028, + 0x0281, + 0x0481, + /* 00011000 */ + /* 00011000 */ + /* 11111111 */ + /* 00011000 */ + /* 11111111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2518,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT UP AND LEFT */ + 0x3025, + 0x0431, + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + /* 11111000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + },{ 0x250c,8,8,SF_FILLRECT,/* BOX DRAWINGS LIGHT DOWN AND RIGHT */ + 0x3451, + 0x3523, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00011111 */ + /* 00011000 */ + /* 00011000 */ + /* 00011000 */ + },{ 0x2588,8,8,SF_FILLRECT,/* FULL BLOCK */ + 0x0088, + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + },{ 0x2584,8,8,SF_FILLRECT,/* LOWER HALF BLOCK */ + 0x0484, + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + },{ 0x258c,8,8,SF_FILLRECT,/* LEFT HALF BLOCK */ + 0x0048, + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + /* 11110000 */ + },{ 0x2590,8,8,SF_FILLRECT,/* RIGHT HALF BLOCK */ + 0x4048, + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + /* 00001111 */ + },{ 0x2580,8,8,SF_FILLRECT,/* UPPER HALF BLOCK */ + 0x0084, + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 11111111 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + /* 00000000 */ + }}; + + public SoftFont() { + font = new java.util.Hashtable(); + for (int i=0;i=0x100) { + System.out.println("Character "+((int)c)+" not in softfont"); + } + return insoftfont; + } + + public void drawChar(Graphics g,char c,int x,int y,int cw,int ch) { + double dw,dh; + Object Ientry; + int w,h,entry,i,fontwidth,fontheight; + + Ientry = font.get(new Integer(c)); + if (Ientry == null) + return; + entry = ((Integer)Ientry).intValue(); + fontwidth = fontdata[entry][SF_WIDTH]; + fontheight = fontdata[entry][SF_HEIGHT]; + + dw = cw*1.0/fontwidth; + dh = ch*1.0/fontheight; + + switch (fontdata[entry][SF_TYPE]) { + case SF_BITMAP: + for (h=0;h>12; + h=(fontdata[entry][i]&0x0F00)>>8; + xw = (fontdata[entry][i]&0x00F0)>>4; + xh = (fontdata[entry][i]&0x000F); + g.fillRect( + x+(int)(w*dw), + y+(int)(h*dh), + ((int)((w+xw)*dw))-(int)(w*dw), + ((int)((h+xh)*dh))-(int)(h*dh) + ); + i++; + } + break; + default: + break; + } + } +} blob - /dev/null blob + baa659369be0ad30a2f8ead65ac57ea3071b7cbb (mode 644) --- /dev/null +++ de/mud/terminal/VDU.java @@ -0,0 +1,1196 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.terminal; + +import java.awt.Graphics; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Point; +import java.awt.Insets; +import java.awt.Event; +import java.awt.Label; +import java.awt.Frame; +import java.awt.Rectangle; + +import java.awt.AWTEvent; + +/** + * Video Display Unit emulation. This class implements all necessary + * features of a character display unit, but not the actual terminal emulation. + * It can be used as the base for terminal emulations of any kind. + *

+ * Maintainer: Matthias L. Jugel + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public class VDU extends Canvas { + /** The current version id tag */ + public final static String ID = "$Id$"; + + /** Enable debug messages. */ + public final static int debug = 0; + + private Dimension size; /* rows and columns */ + private Insets insets; /* size of the border */ + private boolean raised; /* indicator if the border is raised */ + + private char charArray[][]; /* contains the characters */ + private int charAttributes[][]; /* contains character attrs */ + private int bufSize, maxBufSize; /* buffer sizes */ + + private int windowBase; /* where the start displaying */ + private int screenBase; /* the actual screen start */ + private int topMargin; /* top scroll margin */ + private int bottomMargin; /* bottom scroll margin */ + + private Font normalFont; /* normal font */ + private FontMetrics fm; /* current font metrics */ + private int charWidth; /* current width of a char */ + private int charHeight; /* current height of a char */ + private int charDescent; /* base line descent */ + private int resizeStrategy; /* current resizing strategy */ + + private int cursorX, cursorY; /* current cursor position */ + private Point selectBegin, selectEnd; /* selection coordinates */ + + private SoftFont sf = new SoftFont(); + + private boolean screenLocked = false; /* screen needs to be locked */ + /* because of paint requests */ + /* during other operations */ + private boolean update[]; /* contains the lines that need update */ + + /** + * Create a color representation that is brighter than the standard + * color but not what we would like to use for bold characters. + * @param clr the standard color + * @return the new brighter color + */ + private Color brighten(Color clr) { + return new Color(Math.max((int) (clr.getRed() *.85), 0), + Math.max((int) (clr.getGreen() * .85), 0), + Math.max((int) (clr.getBlue() * .85), 0)); + } + + /** A list of colors used for representation of the display */ + private Color color[] = { brighten(Color.black), + brighten(Color.red), + brighten(Color.green), + brighten(Color.yellow), + brighten(Color.blue), + brighten(Color.magenta), + brighten(Color.cyan), + brighten(Color.white), + }; + + public final static int COLOR_0 = 0; + public final static int COLOR_1 = 1; + public final static int COLOR_2 = 2; + public final static int COLOR_3 = 3; + public final static int COLOR_4 = 4; + public final static int COLOR_5 = 5; + public final static int COLOR_6 = 6; + public final static int COLOR_7 = 7; + + /* definitions of standards for the display unit */ + private static int COLOR_FG_STD = 7; + private static int COLOR_FG_BOLD = 3; + private static int COLOR_BG_STD = 0; + private final static int COLOR = 0x7f8; + private final static int COLOR_FG = 0x78; + private final static int COLOR_BG = 0x780; + + /** Scroll up when inserting a line. */ + public final static boolean SCROLL_UP = false; + /** Scroll down when inserting a line. */ + public final static boolean SCROLL_DOWN = true; + + /** Do nothing when the component is resized. */ + public final static int RESIZE_NONE = 0; + /** Resize the width and height of the character screen. */ + public final static int RESIZE_SCREEN = 1; + /** Resize the font to the new screen size. */ + public final static int RESIZE_FONT = 2; + + /** Make character normal. */ + public final static int NORMAL = 0x00; + /** Make character bold. */ + public final static int BOLD = 0x01; + /** Underline character. */ + public final static int UNDERLINE = 0x02; + /** Invert character. */ + public final static int INVERT = 0x04; + + /** + * Create a new video display unit with the passed width and height in + * characters using a special font and font size. These features can + * be set independently using the appropriate properties. + * @param width the length of the character lines + * @param height the amount of lines on the screen + * @param font the font to be used (usually Monospaced) + */ + public VDU(int width, int height, Font font) { + // set the normal font to use + setFont(font); + // set the standard resize strategy + setResizeStrategy(RESIZE_FONT); + // set the display screen size + setScreenSize(width, height); + + selectBegin = new Point(0,0); + selectEnd = new Point(0,0); + } + + /** + * Create a display unit with specific size, Font is "Monospaced", size 12. + * @param width the length of the character lines + * @param height the amount of lines on the screen + */ + public VDU(int width, int height) { + this(width, height, new Font("Monospaced", Font.PLAIN, 12)); + } + + /** + * Create a display with the font passed and size 80x24. + * @param font the font to be used (usually Monospaced) + */ + public VDU(Font font) { + this(80, 24, font); + } + + /** + * Create a display unit with size 80x24 and Font "Monospaced", size 12. + */ + public VDU() { + this(80, 24, new Font("Monospaced", Font.PLAIN, 12)); + } + + public void setColorSet(Color[] colorset) { + System.arraycopy(colorset, 0, color, 0, 8); + } + + public Color[] getColorSet() { + return color; + } + + /** + * Put a character on the screen with normal font and outline. + * The character previously on that position will be overwritten. + * You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param ch the character to show on the screen + * @see #insertChar + * @see #deleteChar + * @see #redraw + */ + public void putChar(int c, int l, char ch) { + putChar(c, l, ch, NORMAL); + } + + /** + * Put a character on the screen with specific font and outline. + * The character previously on that position will be overwritten. + * You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param ch the character to show on the screen + * @param attributes the character attributes + * @see #BOLD + * @see #UNDERLINE + * @see #INVERT + * @see #NORMAL + * @see #insertChar + * @see #deleteChar + * @see #redraw + */ + + public void putChar(int c, int l, char ch, int attributes) { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + charArray[screenBase + l][c] = ch; + charAttributes[screenBase + l][c] = attributes; + markLine(l, 1); + } + + /** + * Get the character at the specified position. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @see #putChar + */ + public char getChar(int c, int l) { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + return charArray[l][c]; + } + + /** + * Get the attributes for the specified position. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @see #putChar + */ + public int getAttributes(int c, int l) { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + return charAttributes[l][c]; + } + + /** + * Insert a character at a specific position on the screen. + * All character right to from this position will be moved one to the right. + * You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param ch the character to insert + * @param attributes the character attributes + * @see #BOLD + * @see #UNDERLINE + * @see #INVERT + * @see #NORMAL + * @see #putChar + * @see #deleteChar + * @see #redraw + */ + public void insertChar(int c, int l, char ch, int attributes) { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + System.arraycopy(charArray[screenBase + l], c, + charArray[screenBase + l], c + 1, size.width - c - 1); + System.arraycopy(charAttributes[screenBase + l], c, + charAttributes[screenBase + l], c + 1, size.width - c - 1); + putChar(c, l, ch, attributes); + } + + /** + * Delete a character at a given position on the screen. + * All characters right to the position will be moved one to the left. + * You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @see #putChar + * @see #insertChar + * @see #redraw + */ + public void deleteChar(int c, int l) { + c = checkBounds(c, 0, size.width - 1); + l = checkBounds(l, 0, size.height - 1); + if(c < size.width - 1) { + System.arraycopy(charArray[screenBase + l], c + 1, + charArray[screenBase + l], c, size.width - c - 1); + System.arraycopy(charAttributes[screenBase + l], c + 1, + charAttributes[screenBase + l], c, size.width - c - 1); + } + putChar(size.width - 1, l, (char)0); + } + + /** + * Put a String at a specific position. Any characters previously on that + * position will be overwritten. You need to call redraw() for screen update. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param s the string to be shown on the screen + * @see #BOLD + * @see #UNDERLINE + * @see #INVERT + * @see #NORMAL + * @see #putChar + * @see #insertLine + * @see #deleteLine + * @see #redraw + */ + public void putString(int c, int l, String s) { + putString(c, l, s, NORMAL); + } + + /** + * Put a String at a specific position giving all characters the same + * attributes. Any characters previously on that position will be + * overwritten. You need to call redraw() to update the screen. + * @param c x-coordinate (column) + * @param l y-coordinate (line) + * @param s the string to be shown on the screen + * @param attributes character attributes + * @see #BOLD + * @see #UNDERLINE + * @see #INVERT + * @see #NORMAL + * @see #putChar + * @see #insertLine + * @see #deleteLine + * @see #redraw + */ + public void putString(int c, int l, String s, int attributes) { + for(int i = 0; i < s.length() && c + i < size.width; i++) + putChar(c + i, l, s.charAt(i), attributes); + } + + /** + * Insert a blank line at a specific position. + * The current line and all previous lines are scrolled one line up. The + * top line is lost. You need to call redraw() to update the screen. + * @param l the y-coordinate to insert the line + * @see #deleteLine + * @see #redraw + */ + public void insertLine(int l) { + insertLine(l, 1, SCROLL_UP); + } + + /** + * Insert blank lines at a specific position. + * You need to call redraw() to update the screen + * @param l the y-coordinate to insert the line + * @param n amount of lines to be inserted + * @see #deleteLine + * @see #redraw + */ + public void insertLine(int l, int n) { + insertLine(l, n, SCROLL_UP); + } + + /** + * Insert a blank line at a specific position. Scroll text according to + * the argument. + * You need to call redraw() to update the screen + * @param l the y-coordinate to insert the line + * @param scrollDown scroll down + * @see #deleteLine + * @see #SCROLL_UP + * @see #SCROLL_DOWN + * @see #redraw + */ + public void insertLine(int l, boolean scrollDown) { + insertLine(l, 1, scrollDown); + } + + /** + * Insert blank lines at a specific position. + * The current line and all previous lines are scrolled one line up. The + * top line is lost. You need to call redraw() to update the screen. + * @param l the y-coordinate to insert the line + * @param n number of lines to be inserted + * @param scrollDown scroll down + * @see #deleteLine + * @see #SCROLL_UP + * @see #SCROLL_DOWN + * @see #redraw + */ + public synchronized void insertLine(int l, int n, boolean scrollDown) { + screenLocked = true; + + l = checkBounds(l, 0, size.height - 1); + + char cbuf[][] = null; + int abuf[][] = null; + int offset = 0; + int oldBase = screenBase; + int top = (l < topMargin ? + 0 : (l > bottomMargin ? + (bottomMargin + 1 < size.height ? + bottomMargin + 1 : size.height - 1) : topMargin)); + int bottom = (l > bottomMargin ? + size.height - 1 : (l < topMargin ? + (topMargin > 0 ? + topMargin - 1 : 0) : bottomMargin)); + + + if(scrollDown) { + if(n > (bottom - top)) n = (bottom - top); + cbuf = new char[bottom - l - (n - 1)][size.width]; + abuf = new int[bottom - l - (n - 1)][size.width]; + + System.arraycopy(charArray, oldBase + l, cbuf, 0, bottom - l - (n - 1)); + System.arraycopy(charAttributes, oldBase + l, + abuf, 0, bottom - l - (n - 1)); + System.arraycopy(cbuf, 0, charArray, oldBase + l + n, + bottom - l - (n - 1)); + System.arraycopy(abuf, 0, charAttributes, oldBase + l + n, + bottom - l - (n - 1)); + cbuf = charArray; + abuf = charAttributes; + } else try { + if(n > (bottom - top) + 1) n = (bottom - top) + 1; + if(bufSize < maxBufSize) { + if(bufSize + n > maxBufSize) { + offset = n - (maxBufSize - bufSize); + bufSize = maxBufSize; + screenBase = maxBufSize - size.height - 1; + windowBase = screenBase; + } else { + screenBase += n; + windowBase += n; + bufSize += n; + } + cbuf = new char[bufSize][size.width]; + abuf = new int[bufSize][size.width]; + } else { + offset = n; + cbuf = charArray; + abuf = charAttributes; + } + // copy anything from the top of the buffer (+offset) to the new top + // up to the screenBase. + if(oldBase > 0) { + System.arraycopy(charArray, offset, + cbuf, 0, + oldBase - offset); + System.arraycopy(charAttributes, offset, + abuf, 0, + oldBase - offset); + } + // copy anything from the top of the screen (screenBase) up to the + // topMargin to the new screen + if(top > 0) { + System.arraycopy(charArray, oldBase, + cbuf, screenBase, + top); + System.arraycopy(charAttributes, oldBase, + abuf, screenBase, + top); + } + // copy anything from the topMargin up to the amount of lines inserted + // to the gap left over between scrollback buffer and screenBase + if(oldBase > 0) { + System.arraycopy(charArray, oldBase + top, + cbuf, oldBase - offset, + n); + System.arraycopy(charAttributes, oldBase + top, + abuf, oldBase - offset, + n); + } + // copy anything from topMargin + n up to the line linserted to the + // topMargin + System.arraycopy(charArray, oldBase + top + n, + cbuf, screenBase + top, + l - top - (n - 1)); + System.arraycopy(charAttributes, oldBase + top + n, + abuf, screenBase + top, + l - top - (n - 1)); + // + // copy the all lines next to the inserted to the new buffer + if(l < size.height - 1) { + System.arraycopy(charArray, oldBase + l + 1, + cbuf, screenBase + l + 1, + (size.height - 1) - l); + System.arraycopy(charAttributes, oldBase + l + 1, + abuf, screenBase + l + 1, + (size.height - 1) - l); + } + } catch(ArrayIndexOutOfBoundsException e) { + // this should not happen anymore, but I will leave the code + // here in case something happens anyway. That code above is + // so complex I always have a hard time understanding what + // I did, even though there are comments + System.err.println("*** Error while scrolling up:"); + System.err.println("--- BEGIN STACK TRACE ---"); + e.printStackTrace(); + System.err.println("--- END STACK TRACE ---"); + System.err.println("bufSize="+bufSize+", maxBufSize="+maxBufSize); + System.err.println("top="+top+", bottom="+bottom); + System.err.println("n="+n+", l="+l); + System.err.println("screenBase="+screenBase+", windowBase="+windowBase); + System.err.println("oldBase="+oldBase); + System.err.println("size.width="+size.width+", size.height="+size.height); + System.err.println("abuf.length="+abuf.length+", cbuf.length="+cbuf.length); + System.err.println("*** done dumping debug information"); + } + + for(int i = 0; i < n; i++) { + cbuf[(screenBase + l) + (scrollDown ? i : -i) ] = new char[size.width]; + abuf[(screenBase + l) + (scrollDown ? i : -i) ] = new int[size.width]; + } + + charArray = cbuf; + charAttributes = abuf; + + if(scrollDown) + markLine(l, bottom - l + 1); + else + markLine(top, l - top + 1); + + screenLocked = false; + } + + /** + * Delete a line at a specific position. Subsequent lines will be scrolled + * up to fill the space and a blank line is inserted at the end of the + * screen. + * @param l the y-coordinate to insert the line + * @see #deleteLine + */ + public void deleteLine(int l) { + l = checkBounds(l, 0, size.height - 1); + + int bottom = (l>bottomMargin?size.height-1: + (l bottomMargin) { + topMargin = bottomMargin; + bottomMargin = l; + } + else + topMargin = l; + if(topMargin < 0) topMargin = 0; + if(bottomMargin > size.height - 1) bottomMargin = size.height - 1; + } + + /** + * Get the top scroll margin. + */ + public int getTopMargin() { + return topMargin; + } + + /** + * Set the bottom scroll margin for the screen. If the current top margin + * is bigger it will become the bottom margin and the line will become the + * top margin. + * @param l line that is the margin + */ + public void setBottomMargin(int l) { + if(l < topMargin) { + bottomMargin = topMargin; + topMargin = l; + } + else + bottomMargin = l; + if(topMargin < 0) topMargin = 0; + if(bottomMargin > size.height - 1) bottomMargin = size.height - 1; + } + + /** + * Get the bottom scroll margin. + */ + public int getBottomMargin() { + return bottomMargin; + } + + /** + * Set scrollback buffer size. + * @param amount new size of the buffer + */ + public void setBufferSize(int amount) { + screenLocked = true; + + if(amount < size.height) amount = size.height; + if(amount < maxBufSize) { + char cbuf[][] = new char[amount][size.width]; + int abuf[][] = new int[amount][size.width]; + if(charArray != null) + System.arraycopy(charArray, bufSize - amount, cbuf, 0, amount); + if(charAttributes != null) + System.arraycopy(charAttributes, bufSize - amount, abuf, 0, amount); + charArray = cbuf; + charAttributes = abuf; + } + maxBufSize = amount; + + screenLocked = false; + + repaint(); + } + + /** + * Retrieve current scrollback buffer size. + * @see #setBufferSize + */ + public int getBufferSize() { + return bufSize; + } + + /** + * Retrieve maximum buffer Size. + * @see #getBufferSize + */ + public int getMaxBufferSize() { + return maxBufSize; + } + + /** + * Set the current window base. This allows to view the scrollback buffer. + * @param line the line where the screen window starts + * @see setBufferSize + * @see getBufferSize + */ + public void setWindowBase(int line) { + if(line > screenBase) line = screenBase; + else if(line < 0) line = 0; + windowBase = line; + repaint(); + } + + /** + * Get the current window base. + * @see setWindowBase + */ + public int getWindowBase() { + return windowBase; + } + + /** + * Set the font to be used for rendering the characters on screen. + * @param font the new font to be used. + */ + public void setFont(Font font) { + super.setFont(normalFont = font); + fm = getFontMetrics(font); + if(fm != null) { + charWidth = fm.charWidth('@'); + charHeight = fm.getHeight(); + charDescent = fm.getDescent(); + } + } + + /** + * Change the size of the screen. This will include adjustment of the + * scrollback buffer. + * @param columns width of the screen + * @param columns height of the screen + */ + public void setScreenSize(int width, int height) { + char cbuf[][]; + int abuf[][]; + int bsize = bufSize; + + if(width < 1 || height < 1) return; + + if(debug > 0) + System.err.println("VDU: screen size ["+width+","+height+"]"); + + screenLocked = true; + + // super.update(getGraphics()); + + if(height > maxBufSize) + maxBufSize = height; + + if(height > bufSize) { + bufSize = height; + screenBase = 0; + windowBase = 0; + } + + cbuf = new char[bufSize][width]; + abuf = new int[bufSize][width]; + + if(charArray != null && charAttributes != null) + for(int i = 0; i < bsize && i < bufSize; i++) { + System.arraycopy(charArray[i], 0, cbuf[i], 0, + width < size.width ? width : size.width); + System.arraycopy(charAttributes[i], 0, abuf[i], 0, + width < size.width ? width : size.width); + } + charArray = cbuf; + charAttributes = abuf; + size = new Dimension(width, height); + topMargin = 0; + bottomMargin = height - 1; + update = new boolean[height + 1]; + for(int i = 0; i <= height; i++) update[i] = true; + screenLocked = false; + } + + /** + * Get the screen size in rows and columns. + */ + public Dimension getScreenSize() { + return size; + } + + /** + * Set the strategy when window is resized. + * RESIZE_FONT is default. + * @param strategy the strategy + * @see #RESIZE_NONE + * @see #RESIZE_FONT + * @see #RESIZE_SCREEN + */ + public void setResizeStrategy(int strategy) { + resizeStrategy = strategy; + } + + /** + * Get amount of rows on the screen. + */ + public int getRows() { return size.height; } + + /** + * Get amount of columns on the screen. + */ + public int getColumns() { return size.width; } + + /** + * Set the border thickness and the border type. + * @param thickness border thickness in pixels, zero means no border + * @param raised a boolean indicating a raised or embossed border + */ + public void setBorder(int thickness, boolean raised) { + if(thickness == 0) insets = null; + else insets = new Insets(thickness+1, thickness+1, + thickness+1, thickness+1); + this.raised = raised; + } + + /** + * Mark lines to be updated with redraw(). + * @param l starting line + * @param n amount of lines to be updated + * @see #redraw + */ + public void markLine(int l, int n) { + l = checkBounds(l, 0, size.height - 1); + for(int i = 0; i < n && l + i < size.height; i++) + update[l + i + 1] = true; + } + + /** + * Redraw marked lines. + * @see #markLine + */ + public void redraw() { + update[0] = true; + repaint(); + } + + /** + * Update the display. to reduce flashing we have overridden this method. + */ + public void update(Graphics g) { + paint(g); + } + + /** + * Paint the current screen. All painting is done here. Only lines that have + * changed will be redrawn! + */ + public synchronized void paint(Graphics g) { + if(screenLocked) return; + int xoffset = (super.getSize().width - size.width * charWidth) / 2; + int yoffset = (super.getSize().height - size.height * charHeight) / 2; + + Color fg = color[COLOR_FG_STD]; + Color bg = color[COLOR_BG_STD]; + + g.setFont(normalFont); + + for(int l = 0; l < size.height; l++) { + if(update[0] && !update[l + 1]) continue; + update[l + 1] = false; + for(int c = 0; c < size.width; c++) { + int addr = 0; + int currAttr = charAttributes[windowBase + l][c]; + + fg = getForeground(); + bg = getBackground(); + // fg = color[COLOR_FG_STD]; + // bg = color[COLOR_BG_STD]; + + // Special handling of BOLD for terminals used on 5ESS + if(((currAttr & BOLD) != 0) && + ((currAttr & COLOR_FG) == 0) && + ((currAttr & COLOR_BG) == 0)) + fg = color[COLOR_FG_BOLD]; + + if ((currAttr & COLOR_FG) != 0) + fg = color[((currAttr & COLOR_FG) >> 3)-1]; + if ((currAttr & COLOR_BG) != 0) + bg = color[((currAttr & COLOR_BG) >> 7)-1]; + + if((currAttr & BOLD) != 0) + if(fg.equals(Color.black)) + fg = Color.gray; + else { + fg = fg.brighter(); + bg = bg.brighter(); + } + + if((currAttr & INVERT) != 0) { Color swapc = bg; bg=fg;fg=swapc; } + + if (sf.inSoftFont(charArray[windowBase + l][c])) { + g.setColor(bg); + g.fillRect(c * charWidth + xoffset, l * charHeight + yoffset, + charWidth, charHeight); + g.setColor(fg); + sf.drawChar(g,charArray[windowBase + l][c],xoffset+c*charWidth, + l*charHeight+yoffset, charWidth, charHeight); + if((currAttr & UNDERLINE) != 0) + g.drawLine(c * charWidth + xoffset, + (l+1) * charHeight - charDescent / 2 + yoffset, + c * charWidth + charWidth + xoffset, + (l+1) * charHeight - charDescent / 2 + yoffset); + continue; + } + + // determine the maximum of characters we can print in one go + while(c + addr < size.width && + charAttributes[windowBase + l][c + addr] == currAttr && + !sf.inSoftFont(charArray[windowBase + l ][c+addr]) + ) { + if(charArray[windowBase + l][c + addr] < ' ') + charArray[windowBase + l][c + addr] = ' '; + addr++; + } + + // clear the part of the screen we want to change (fill rectangle) + g.setColor(bg); + g.fillRect(c * charWidth + xoffset, l * charHeight + yoffset, + addr * charWidth, charHeight); + + g.setColor(fg); + + // draw the characters + g.drawChars(charArray[windowBase + l], c, addr, + c * charWidth + xoffset, + (l+1) * charHeight - charDescent + yoffset); + + if((currAttr & UNDERLINE) != 0) + g.drawLine(c * charWidth + xoffset, + (l+1) * charHeight - charDescent / 2 + yoffset, + c * charWidth + addr * charWidth + xoffset, + (l+1) * charHeight - charDescent / 2 + yoffset); + + c += addr - 1; + } + } + + // draw cursor + if(screenBase + cursorY >= windowBase && + screenBase + cursorY < windowBase + size.height) { + g.setColor(color[COLOR_FG_STD]); + g.setXORMode(color[COLOR_BG_STD]); + g.fillRect( cursorX * charWidth + xoffset, + (cursorY + screenBase - windowBase) * charHeight + yoffset, + charWidth, charHeight); + g.setPaintMode(); + } + + if(windowBase <= selectBegin.y || windowBase <= selectEnd.y) { + int beginLine = selectBegin.y - windowBase; + int endLine = selectEnd.y - selectBegin.y; + if(beginLine < 0) { + endLine += beginLine; + beginLine = 0; + } + if(endLine > size.height) endLine = size.height - beginLine; + + g.setXORMode(color[COLOR_BG_STD]); + g.fillRect(selectBegin.x * charWidth + xoffset, + beginLine * charHeight + yoffset, + (endLine == 0 ? (selectEnd.x - selectBegin.x) : + (size.width - selectBegin.x)) + * charWidth, + charHeight); + if(endLine > 1) + g.fillRect(0 + xoffset, + (beginLine + 1) * charHeight + yoffset, + size.width * charWidth, + (endLine - 1) * charHeight); + if(endLine > 0) + g.fillRect(0 + xoffset, + (beginLine + endLine) * charHeight + yoffset, + selectEnd.x * charWidth, + charHeight); + g.setPaintMode(); + } + + if(insets != null) { + g.setColor(getBackground()); + xoffset--; yoffset--; + for(int i = insets.top - 1; i >= 0; i--) + g.draw3DRect(xoffset - i, yoffset - i, + charWidth * size.width + 1 + i * 2, + charHeight * size.height + 1 + i * 2, + raised); + } + + update[0] = false; + } + + private int checkBounds(int value, int lower, int upper) { + if(value < lower) return lower; + if(value > upper) return upper; + return value; + } + + /** + * Reshape character display according to resize strategy. + * @see #setResizeStrategy + */ + public void setBounds(int x, int y, int w, int h) { + if(debug > 0) + System.err.println("VDU: setBounds("+x+","+y+","+w+","+h+")"); + + int xborder = 0, yborder = 0; + + if(insets != null) { + w -= (xborder = insets.left + insets.right); + h -= (yborder = insets.top + insets.bottom); + } + + if(debug > 0) + System.err.println("VDU: looking for better match for "+normalFont); + + Font tmpFont = normalFont; + String fontName = normalFont.getName(); + fm = getFontMetrics(normalFont); + if(fm != null) { + charWidth = fm.charWidth('@'); + charHeight = fm.getHeight(); + } + + switch(resizeStrategy) { + case RESIZE_SCREEN: + setScreenSize(w / charWidth, size.height = h / charHeight); + break; + case RESIZE_FONT: + int height = h / size.height; + int width = w / size.width; + + fm = getFontMetrics(normalFont = new Font(fontName, Font.PLAIN, + charHeight)); + + // adapt current font size (from small up to best fit) + if(fm.getHeight() < height || fm.charWidth('@') < width) + do { + fm = getFontMetrics(normalFont = new Font(fontName, Font.PLAIN, + ++charHeight)); + } while(fm.getHeight() < height || fm.charWidth('@') < width); + + // now check if we got a font that is too large + if(fm.getHeight() > height || fm.charWidth('@') > width) + do { + fm = getFontMetrics(normalFont = new Font(fontName, Font.PLAIN, + --charHeight)); + } while(charHeight > 1 && + (fm.getHeight() > height || + fm.charWidth('@') > width)); + + if(charHeight <= 1) { + System.err.println("VDU: error during resize, resetting"); + normalFont = tmpFont; + System.err.println("VDU: disabling font/screen resize"); + resizeStrategy = RESIZE_NONE; + } + + setFont(normalFont); + fm = getFontMetrics(normalFont); + charWidth = fm.charWidth('@'); + charHeight = fm.getHeight(); + charDescent = fm.getDescent(); + break; + case RESIZE_NONE: + default: + break; + } + if(debug > 0) { + System.err.println("VDU: charWidth="+charWidth+", "+ + "charHeight="+charHeight+", "+ + "charDescent="+charDescent); + } + + // now set the bounds for the whole component accordingly + super.setBounds(x, y, w + xborder, h + yborder); + } + + /** + * Return the real size in points of the character display. + * @return Dimension the dimension of the display + * @see java.awt.Dimension + */ + public Dimension getSize() { + int xborder = 0, yborder = 0; + if(insets != null) { + xborder = insets.left + insets.right; + yborder = insets.top + insets.bottom; + } + return new Dimension(size.width * charWidth + xborder, + size.height * charHeight + yborder); + } + + /** + * Return the preferred Size of the character display. + * This turns out to be the actual size. + * @return Dimension dimension of the display + * @see size + */ + public Dimension getPreferredSize() { + return getSize(); + } + + /** + * The insets of the character display define the border. + * @return Insets border thickness in pixels + */ + public Insets getInsets() { + return insets; + } + + /** + * Handle mouse events for copy & paste + * @param evt the event that occured + * @return boolean true if action was taken + * @see java.awt.Event + */ + /* + public void mouseDown(MouseEvent evt) { + // handle scrollbar events + if(evt != null && evt.arg != null) { + int val = ((Integer)evt.arg).intValue(); + setWindowBase(val); + return true; + } + + if(evt.id == Event.MOUSE_DOWN || evt.id == Event.MOUSE_UP || + evt.id == Event.MOUSE_DRAG) { + int xoffset = (super.size().width - size.width * charWidth) / 2; + int yoffset = (super.size().height - size.height * charHeight) / 2; + switch(evt.id) { + case Event.MOUSE_DOWN: + selectBegin.x = (evt.x - xoffset) / charWidth; + selectBegin.y = (evt.y - yoffset) / charHeight + windowBase; + selectEnd.x = selectBegin.x; + selectEnd.y = selectBegin.y; + break; + case Event.MOUSE_UP: + case Event.MOUSE_DRAG: + int x = (evt.x - xoffset) / charWidth; + int y = (evt.y - yoffset) / charHeight + windowBase; + int oldx = selectEnd.x, oldy = selectEnd.y; + + if((x < selectBegin.x && y < selectBegin.y) && + (x < selectEnd.x && y < selectEnd.y)) { + selectBegin.x = x; + selectBegin.y = y; + } else { + selectEnd.x = x; + selectEnd.y = y; + } + + if(evt.id == Event.MOUSE_UP) { + if(selectBegin.x == selectEnd.x && + selectBegin.y == selectEnd.y) { + repaint(); + return true; + } + String tmp = ""; + // fix end.x and end.y, they can get over the border + if (selectEnd.x < 0) selectEnd.x = 0; + if (selectEnd.y < 0) selectEnd.y = 0; + if (selectEnd.y >= charArray.length) { + selectEnd.y = charArray.length-1; + } + if (selectEnd.x >= charArray[0].length) { + selectEnd.x = charArray[0].length-1; + } + for(int l = selectBegin.y; l <= selectEnd.y; l++) + if(l == selectBegin.y) + tmp = (new String(charArray[l])).substring(selectBegin.x) + "\n"; + else if(l == selectEnd.y) + tmp += (new String(charArray[l])).substring(0, selectEnd.x); + else tmp += new String(charArray[l]) + "\n"; + + // for jdk-1.1 + // String s=(String) ((StringSelection)this.getToolkit(). + // getSystemClipboard(). + // getContents(this)). + // getTransferData(DataFlavor.stringFlavor); + // System.out.println(s); + // + repaint(); + } else + if(oldx != x || oldy != y) repaint(); + break; + } + return true; + } + return false; + } + */ +} blob - /dev/null blob + 86d5f70125316fb6b421c8f612f3dc58a74b1ade (mode 644) --- /dev/null +++ de/mud/terminal/vt320.java @@ -0,0 +1,1878 @@ +/* + * This file is part of "The Java Telnet Application". + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * "The Java Telnet Application" 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. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +package de.mud.terminal; + +import java.awt.Font; +import java.awt.Dimension; +import java.awt.Event; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import java.util.Properties; + +/** + * Implementation of a VT terminal emulation plus ANSI compatible. + *

+ * Maintainer: Marcus Meißner + * + * @version $Id$ + * @author Matthias L. Jugel, Marcus Meißner + */ +public abstract class vt320 extends VDU implements KeyListener { + /** The current version id tag.

+ * $Id$ + */ + public final static String ID = "$Id$"; + + /** the debug level */ + private final static int debug = 0; + + /** + * Write an answer back to the remote host. This is needed to be able to + * send terminal answers requests like status and type information. + * @param b the array of bytes to be sent + */ + protected abstract void write(byte[] b); + + /** + * Put string at current cursor position. Moves cursor + * according to the String. Does NOT wrap. + * @param s the string + */ + public void putString(String s) { + int i,len=s.length(); + + markLine(R,1); + for (i=0;i Unicode mapping + // Unicode DEC Unicode name (DEC name) + private static char DECSPECIAL[] = { + '\u0040', //5f blank + '\u2666', //60 black diamond + '\u2592', //61 grey square + '\u2409', //62 Horizontal tab (ht) pict. for control + '\u240c', //63 Form Feed (ff) pict. for control + '\u240d', //64 Carriage Return (cr) pict. for control + '\u240a', //65 Line Feed (lf) pict. for control + '\u00ba', //66 Masculine ordinal indicator + '\u00b1', //67 Plus or minus sign + '\u2424', //68 New Line (nl) pict. for control + '\u240b', //69 Vertical Tab (vt) pict. for control + '\u2518', //6a Forms light up and left + '\u2510', //6b Forms light down and left + '\u250c', //6c Forms light down and right + '\u2514', //6d Forms light up and right + '\u253c', //6e Forms light vertical and horizontal + '\u2594', //6f Upper 1/8 block (Scan 1) + '\u2580', //70 Upper 1/2 block (Scan 3) + '\u2500', //71 Forms light horizontal or ?em dash? (Scan 5) + '\u25ac', //72 \u25ac black rect. or \u2582 lower 1/4 (Scan 7) + '\u005f', //73 \u005f underscore or \u2581 lower 1/8 (Scan 9) + '\u251c', //74 Forms light vertical and right + '\u2524', //75 Forms light vertical and left + '\u2534', //76 Forms light up and horizontal + '\u252c', //77 Forms light down and horizontal + '\u2502', //78 vertical bar + '\u2264', //79 less than or equal + '\u2265', //7a greater than or equal + '\u00b6', //7b paragraph + '\u2260', //7c not equal + '\u00a3', //7d Pound Sign (british) + '\u00b7' //7e Middle Dot + }; + + /** Strings to send on function key pressing */ + private String FunctionKey[]; + private String FunctionKeyShift[]; + private String FunctionKeyCtrl[]; + private String FunctionKeyAlt[]; + private String KeyUp,KeyDown,KeyLeft,KeyRight,KeyTab,KeyBacktab; + + private String KP0, KP1, KP2, KP3, KP4, KP5, KP6, KP7, KP8, KP9; + private String KPMinus, KPComma, KPPeriod,KPEnter; + private String PF1, PF2, PF3, PF4; + private String Help, Do, Find, Select; + + private String KeyHome[], KeyEnd[], Insert[], Remove[], PrevScn[], NextScn[]; + + private String osc,dcs; /* to memorize OSC & DCS control sequence */ + + private int term_state = TSTATE_DATA; + private boolean vms = false; + private byte[] Tabs; + private int[] DCEvars = new int [10]; + private int DCEvar; + + /** + * Replace escape code characters (backslash + identifier) with their + * respective codes. + * @param tmp the string to be parsed + * @return a unescaped string + */ + static String unEscape(String tmp) { + int idx = 0, oldidx = 0; + String cmd; + + cmd = ""; + while((idx = tmp.indexOf('\\', oldidx)) >= 0 && + ++idx <= tmp.length()) { + cmd += tmp.substring(oldidx, idx-1); + if(idx == tmp.length()) return cmd; + switch(tmp.charAt(idx)) { + case 'b': cmd += "\b"; break; + case 'e': cmd += "\u001b"; break; + case 'n': cmd += "\n"; break; + case 'r': cmd += "\r"; break; + case 't': cmd += "\t"; break; + case 'v': cmd += "\u000b"; break; + case 'a': cmd += "\u0012"; break; + default : + if ( (tmp.charAt(idx)>='0') && (tmp.charAt(idx)<='9')) { + for (i = idx;i'9')) + break; + cmd += (char)Integer.parseInt(tmp.substring(idx, i)); + idx = i-1; + } else + cmd += tmp.substring(idx, ++idx);break; + } + oldidx = ++idx; + } + if(oldidx <= tmp.length()) cmd += tmp.substring(oldidx); + return cmd; + } + + /** + * Not used. + */ + public void keyTyped(KeyEvent evt) { + // nothing to to, however maybe we should use it? + } + + /** + * Not used. + */ + public void keyReleased(KeyEvent evt) { + // nothing to to, however maybe we should use it? + } + + /** + * Handle events for the terminal. Only accept events for the scroll + * bar. Any other events have to be propagated to the parent. + * @param evt the event + */ + public void keyPressed(KeyEvent evt) { + boolean control = evt.isControlDown(); + boolean shift = evt.isShiftDown(); + boolean alt = evt.isAltDown(); + + int keyCode = evt.getKeyCode(); + char keyChar = evt.getKeyChar(); + + if(pressedKey == KeyEvent.VK_ENTER && + (keyCode == KeyEvent.VK_ENTER || keyChar == 10) + && evt.getWhen() - pressedWhen < 50) + // Ray: Elliminate stuttering enter/return + return; + + pressedWhen = evt.getWhen(); + + if(keyCode == KeyEvent.VK_ENTER && !control) { + if(sendcrlf) + write("\r\n"); /* YES, see RFC 854 */ + else + write("\r"); /* YES, see RFC 854 */ + } + + // FIXME: on german PC keyboards you have to use Alt-Ctrl-q to get an @, + // so we can't just use it here... will probably break some other VMS + // codes. -Marcus + // if(((!vms && keyChar == '2') || keyChar == '@' || keyChar == ' ') + // && control) + if (((!vms && keyChar == '2') || keyChar == ' ') && control) + write("" + (char)0); + + if(vms) { + if (keyChar == 8) { + if(shift && !control) + write("" + (char)10); // VMS shift deletes word back + else if(control && !shift) + write("" + (char)24); // VMS control deletes line back + else + write("" + (char)127); // VMS other is delete + } else if(keyChar == 127 && !control) { + if (shift) + write(Insert[0]); // VMS shift delete = insert + else + write(Remove[0]); // VMS delete = remove + } else if(control) + switch(keyChar) { + case '0': + write(KP0); return; + case '1': + write(KP1); return; + case '2': + write(KP2); return; + case '3': + write(KP3); return; + case '4': + write(KP4); return; + case '5': + write(KP5); return; + case '6': + write(KP6); return; + case '7': + write(KP7); return; + case '8': + write(KP8); return; + case '9': + write(KP9); return; + case '.': + write(KPPeriod); return; + case '-': + case 31: + write(KPMinus); return; + case '+': + write(KPComma); return; + case 10: + write(KPEnter); return; + case '/': + write(PF2); return; + case '*': + write(PF3); return; + } + if (shift && keyChar < 32) + write(PF1+(char)(keyChar + 64)); + return; + } + + String fmap[]; + int xind; + xind = 0; + fmap = FunctionKey; + if(shift) { fmap = FunctionKeyShift; xind=1; } + if(control) { fmap = FunctionKeyCtrl; xind=2; } + if(alt) { fmap = FunctionKeyAlt; xind=3; } + + switch (keyCode) { + case KeyEvent.VK_F1: + write(fmap[1]); return; + case KeyEvent.VK_F2: + write(fmap[2]); return; + case KeyEvent.VK_F3: + write(fmap[3]); return; + case KeyEvent.VK_F4: + write(fmap[4]); return; + case KeyEvent.VK_F5: + write(fmap[5]); return; + case KeyEvent.VK_F6: + write(fmap[6]); return; + case KeyEvent.VK_F7: + write(fmap[7]); return; + case KeyEvent.VK_F8: + write(fmap[8]); return; + case KeyEvent.VK_F9: + write(fmap[9]); return; + case KeyEvent.VK_F10: + write(fmap[10]); return; + case KeyEvent.VK_F11: + write(fmap[11]); return; + case KeyEvent.VK_F12: + write(fmap[12]); return; + case KeyEvent.VK_UP: + write(KeyUp); return; + case KeyEvent.VK_DOWN: + write(KeyDown); return; + case KeyEvent.VK_LEFT: + write(KeyLeft); return; + case KeyEvent.VK_RIGHT: + write(KeyRight); return; + case KeyEvent.VK_PAGE_DOWN: + write(NextScn[xind]); return; + case KeyEvent.VK_PAGE_UP: + write(PrevScn[xind]); return; + case KeyEvent.VK_INSERT: + write(Insert[xind]); return; + case KeyEvent.VK_HOME: + if(vms) + write("" + (char)8); + else + write(KeyHome[xind]); + return; + case KeyEvent.VK_END: + if(vms) + write("" + (char)5); + else + write(KeyEnd[xind]); + return; + case KeyEvent.VK_NUM_LOCK: + if(vms && control) + if(pressedKey != keyCode) { + pressedKey = keyCode; + write(PF1); + } else + // Here, we eat a second numlock since that returns numlock state + pressedKey = ' '; + if(!control) + numlock = !numlock; + return; + case KeyEvent.VK_CAPS_LOCK: + capslock = !capslock; + return; + default: + if(debug > 0) + System.out.println("vt320: unknown event: "+evt); + } + + // Hmmm. Outside the VMS case? + if(shift && (keyChar == '\t')) + write(KeyBacktab); + else if (alt) + write(""+((char)(keyChar|0x80))); + else if(capslock) + write((""+keyChar).toUpperCase()); + else + write(""+keyChar); + } + + private void handle_dcs(String dcs) { + System.out.println("DCS: "+dcs); + } + private void handle_osc(String osc) { + System.out.println("OSC: "+osc); + } + + private final static char unimap[] = { + //# + //# Name: cp437_DOSLatinUS to Unicode table + //# Unicode version: 1.1 + //# Table version: 1.1 + //# Table format: Format A + //# Date: 03/31/95 + //# Authors: Michel Suignard + //# Lori Hoerth + //# General notes: none + //# + //# Format: Three tab-separated columns + //# Column #1 is the cp1255_WinHebrew code (in hex) + //# Column #2 is the Unicode (in hex as 0xXXXX) + //# Column #3 is the Unicode name (follows a comment sign, '#') + //# + //# The entries are in cp437_DOSLatinUS order + //# + + 0x0000,// #NULL + 0x0001,// #START OF HEADING + 0x0002,// #START OF TEXT + 0x0003,// #END OF TEXT + 0x0004,// #END OF TRANSMISSION + 0x0005,// #ENQUIRY + 0x0006,// #ACKNOWLEDGE + 0x0007,// #BELL + 0x0008,// #BACKSPACE + 0x0009,// #HORIZONTAL TABULATION + 0x000a,// #LINE FEED + 0x000b,// #VERTICAL TABULATION + 0x000c,// #FORM FEED + 0x000d,// #CARRIAGE RETURN + 0x000e,// #SHIFT OUT + 0x000f,// #SHIFT IN + 0x0010,// #DATA LINK ESCAPE + 0x0011,// #DEVICE CONTROL ONE + 0x0012,// #DEVICE CONTROL TWO + 0x0013,// #DEVICE CONTROL THREE + 0x0014,// #DEVICE CONTROL FOUR + 0x0015,// #NEGATIVE ACKNOWLEDGE + 0x0016,// #SYNCHRONOUS IDLE + 0x0017,// #END OF TRANSMISSION BLOCK + 0x0018,// #CANCEL + 0x0019,// #END OF MEDIUM + 0x001a,// #SUBSTITUTE + 0x001b,// #ESCAPE + 0x001c,// #FILE SEPARATOR + 0x001d,// #GROUP SEPARATOR + 0x001e,// #RECORD SEPARATOR + 0x001f,// #UNIT SEPARATOR + 0x0020,// #SPACE + 0x0021,// #EXCLAMATION MARK + 0x0022,// #QUOTATION MARK + 0x0023,// #NUMBER SIGN + 0x0024,// #DOLLAR SIGN + 0x0025,// #PERCENT SIGN + 0x0026,// #AMPERSAND + 0x0027,// #APOSTROPHE + 0x0028,// #LEFT PARENTHESIS + 0x0029,// #RIGHT PARENTHESIS + 0x002a,// #ASTERISK + 0x002b,// #PLUS SIGN + 0x002c,// #COMMA + 0x002d,// #HYPHEN-MINUS + 0x002e,// #FULL STOP + 0x002f,// #SOLIDUS + 0x0030,// #DIGIT ZERO + 0x0031,// #DIGIT ONE + 0x0032,// #DIGIT TWO + 0x0033,// #DIGIT THREE + 0x0034,// #DIGIT FOUR + 0x0035,// #DIGIT FIVE + 0x0036,// #DIGIT SIX + 0x0037,// #DIGIT SEVEN + 0x0038,// #DIGIT EIGHT + 0x0039,// #DIGIT NINE + 0x003a,// #COLON + 0x003b,// #SEMICOLON + 0x003c,// #LESS-THAN SIGN + 0x003d,// #EQUALS SIGN + 0x003e,// #GREATER-THAN SIGN + 0x003f,// #QUESTION MARK + 0x0040,// #COMMERCIAL AT + 0x0041,// #LATIN CAPITAL LETTER A + 0x0042,// #LATIN CAPITAL LETTER B + 0x0043,// #LATIN CAPITAL LETTER C + 0x0044,// #LATIN CAPITAL LETTER D + 0x0045,// #LATIN CAPITAL LETTER E + 0x0046,// #LATIN CAPITAL LETTER F + 0x0047,// #LATIN CAPITAL LETTER G + 0x0048,// #LATIN CAPITAL LETTER H + 0x0049,// #LATIN CAPITAL LETTER I + 0x004a,// #LATIN CAPITAL LETTER J + 0x004b,// #LATIN CAPITAL LETTER K + 0x004c,// #LATIN CAPITAL LETTER L + 0x004d,// #LATIN CAPITAL LETTER M + 0x004e,// #LATIN CAPITAL LETTER N + 0x004f,// #LATIN CAPITAL LETTER O + 0x0050,// #LATIN CAPITAL LETTER P + 0x0051,// #LATIN CAPITAL LETTER Q + 0x0052,// #LATIN CAPITAL LETTER R + 0x0053,// #LATIN CAPITAL LETTER S + 0x0054,// #LATIN CAPITAL LETTER T + 0x0055,// #LATIN CAPITAL LETTER U + 0x0056,// #LATIN CAPITAL LETTER V + 0x0057,// #LATIN CAPITAL LETTER W + 0x0058,// #LATIN CAPITAL LETTER X + 0x0059,// #LATIN CAPITAL LETTER Y + 0x005a,// #LATIN CAPITAL LETTER Z + 0x005b,// #LEFT SQUARE BRACKET + 0x005c,// #REVERSE SOLIDUS + 0x005d,// #RIGHT SQUARE BRACKET + 0x005e,// #CIRCUMFLEX ACCENT + 0x005f,// #LOW LINE + 0x0060,// #GRAVE ACCENT + 0x0061,// #LATIN SMALL LETTER A + 0x0062,// #LATIN SMALL LETTER B + 0x0063,// #LATIN SMALL LETTER C + 0x0064,// #LATIN SMALL LETTER D + 0x0065,// #LATIN SMALL LETTER E + 0x0066,// #LATIN SMALL LETTER F + 0x0067,// #LATIN SMALL LETTER G + 0x0068,// #LATIN SMALL LETTER H + 0x0069,// #LATIN SMALL LETTER I + 0x006a,// #LATIN SMALL LETTER J + 0x006b,// #LATIN SMALL LETTER K + 0x006c,// #LATIN SMALL LETTER L + 0x006d,// #LATIN SMALL LETTER M + 0x006e,// #LATIN SMALL LETTER N + 0x006f,// #LATIN SMALL LETTER O + 0x0070,// #LATIN SMALL LETTER P + 0x0071,// #LATIN SMALL LETTER Q + 0x0072,// #LATIN SMALL LETTER R + 0x0073,// #LATIN SMALL LETTER S + 0x0074,// #LATIN SMALL LETTER T + 0x0075,// #LATIN SMALL LETTER U + 0x0076,// #LATIN SMALL LETTER V + 0x0077,// #LATIN SMALL LETTER W + 0x0078,// #LATIN SMALL LETTER X + 0x0079,// #LATIN SMALL LETTER Y + 0x007a,// #LATIN SMALL LETTER Z + 0x007b,// #LEFT CURLY BRACKET + 0x007c,// #VERTICAL LINE + 0x007d,// #RIGHT CURLY BRACKET + 0x007e,// #TILDE + 0x007f,// #DELETE + 0x00c7,// #LATIN CAPITAL LETTER C WITH CEDILLA + 0x00fc,// #LATIN SMALL LETTER U WITH DIAERESIS + 0x00e9,// #LATIN SMALL LETTER E WITH ACUTE + 0x00e2,// #LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00e4,// #LATIN SMALL LETTER A WITH DIAERESIS + 0x00e0,// #LATIN SMALL LETTER A WITH GRAVE + 0x00e5,// #LATIN SMALL LETTER A WITH RING ABOVE + 0x00e7,// #LATIN SMALL LETTER C WITH CEDILLA + 0x00ea,// #LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00eb,// #LATIN SMALL LETTER E WITH DIAERESIS + 0x00e8,// #LATIN SMALL LETTER E WITH GRAVE + 0x00ef,// #LATIN SMALL LETTER I WITH DIAERESIS + 0x00ee,// #LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00ec,// #LATIN SMALL LETTER I WITH GRAVE + 0x00c4,// #LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00c5,// #LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00c9,// #LATIN CAPITAL LETTER E WITH ACUTE + 0x00e6,// #LATIN SMALL LIGATURE AE + 0x00c6,// #LATIN CAPITAL LIGATURE AE + 0x00f4,// #LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00f6,// #LATIN SMALL LETTER O WITH DIAERESIS + 0x00f2,// #LATIN SMALL LETTER O WITH GRAVE + 0x00fb,// #LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00f9,// #LATIN SMALL LETTER U WITH GRAVE + 0x00ff,// #LATIN SMALL LETTER Y WITH DIAERESIS + 0x00d6,// #LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00dc,// #LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00a2,// #CENT SIGN + 0x00a3,// #POUND SIGN + 0x00a5,// #YEN SIGN + 0x20a7,// #PESETA SIGN + 0x0192,// #LATIN SMALL LETTER F WITH HOOK + 0x00e1,// #LATIN SMALL LETTER A WITH ACUTE + 0x00ed,// #LATIN SMALL LETTER I WITH ACUTE + 0x00f3,// #LATIN SMALL LETTER O WITH ACUTE + 0x00fa,// #LATIN SMALL LETTER U WITH ACUTE + 0x00f1,// #LATIN SMALL LETTER N WITH TILDE + 0x00d1,// #LATIN CAPITAL LETTER N WITH TILDE + 0x00aa,// #FEMININE ORDINAL INDICATOR + 0x00ba,// #MASCULINE ORDINAL INDICATOR + 0x00bf,// #INVERTED QUESTION MARK + 0x2310,// #REVERSED NOT SIGN + 0x00ac,// #NOT SIGN + 0x00bd,// #VULGAR FRACTION ONE HALF + 0x00bc,// #VULGAR FRACTION ONE QUARTER + 0x00a1,// #INVERTED EXCLAMATION MARK + 0x00ab,// #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00bb,// #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x2591,// #LIGHT SHADE + 0x2592,// #MEDIUM SHADE + 0x2593,// #DARK SHADE + 0x2502,// #BOX DRAWINGS LIGHT VERTICAL + 0x2524,// #BOX DRAWINGS LIGHT VERTICAL AND LEFT + 0x2561,// #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE + 0x2562,// #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE + 0x2556,// #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE + 0x2555,// #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE + 0x2563,// #BOX DRAWINGS DOUBLE VERTICAL AND LEFT + 0x2551,// #BOX DRAWINGS DOUBLE VERTICAL + 0x2557,// #BOX DRAWINGS DOUBLE DOWN AND LEFT + 0x255d,// #BOX DRAWINGS DOUBLE UP AND LEFT + 0x255c,// #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE + 0x255b,// #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE + 0x2510,// #BOX DRAWINGS LIGHT DOWN AND LEFT + 0x2514,// #BOX DRAWINGS LIGHT UP AND RIGHT + 0x2534,// #BOX DRAWINGS LIGHT UP AND HORIZONTAL + 0x252c,// #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + 0x251c,// #BOX DRAWINGS LIGHT VERTICAL AND RIGHT + 0x2500,// #BOX DRAWINGS LIGHT HORIZONTAL + 0x253c,// #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + 0x255e,// #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE + 0x255f,// #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE + 0x255a,// #BOX DRAWINGS DOUBLE UP AND RIGHT + 0x2554,// #BOX DRAWINGS DOUBLE DOWN AND RIGHT + 0x2569,// #BOX DRAWINGS DOUBLE UP AND HORIZONTAL + 0x2566,// #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + 0x2560,// #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + 0x2550,// #BOX DRAWINGS DOUBLE HORIZONTAL + 0x256c,// #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + 0x2567,// #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE + 0x2568,// #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE + 0x2564,// #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE + 0x2565,// #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE + 0x2559,// #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE + 0x2558,// #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE + 0x2552,// #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE + 0x2553,// #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE + 0x256b,// #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE + 0x256a,// #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE + 0x2518,// #BOX DRAWINGS LIGHT UP AND LEFT + 0x250c,// #BOX DRAWINGS LIGHT DOWN AND RIGHT + 0x2588,// #FULL BLOCK + 0x2584,// #LOWER HALF BLOCK + 0x258c,// #LEFT HALF BLOCK + 0x2590,// #RIGHT HALF BLOCK + 0x2580,// #UPPER HALF BLOCK + 0x03b1,// #GREEK SMALL LETTER ALPHA + 0x00df,// #LATIN SMALL LETTER SHARP S + 0x0393,// #GREEK CAPITAL LETTER GAMMA + 0x03c0,// #GREEK SMALL LETTER PI + 0x03a3,// #GREEK CAPITAL LETTER SIGMA + 0x03c3,// #GREEK SMALL LETTER SIGMA + 0x00b5,// #MICRO SIGN + 0x03c4,// #GREEK SMALL LETTER TAU + 0x03a6,// #GREEK CAPITAL LETTER PHI + 0x0398,// #GREEK CAPITAL LETTER THETA + 0x03a9,// #GREEK CAPITAL LETTER OMEGA + 0x03b4,// #GREEK SMALL LETTER DELTA + 0x221e,// #INFINITY + 0x03c6,// #GREEK SMALL LETTER PHI + 0x03b5,// #GREEK SMALL LETTER EPSILON + 0x2229,// #INTERSECTION + 0x2261,// #IDENTICAL TO + 0x00b1,// #PLUS-MINUS SIGN + 0x2265,// #GREATER-THAN OR EQUAL TO + 0x2264,// #LESS-THAN OR EQUAL TO + 0x2320,// #TOP HALF INTEGRAL + 0x2321,// #BOTTOM HALF INTEGRAL + 0x00f7,// #DIVISION SIGN + 0x2248,// #ALMOST EQUAL TO + 0x00b0,// #DEGREE SIGN + 0x2219,// #BULLET OPERATOR + 0x00b7,// #MIDDLE DOT + 0x221a,// #SQUARE ROOT + 0x207f,// #SUPERSCRIPT LATIN SMALL LETTER N + 0x00b2,// #SUPERSCRIPT TWO + 0x25a0,// #BLACK SQUARE + 0x00a0,// #NO-BREAK SPACE + }; + + public char map_cp850_unicode(char x) { + if (x>=0x100) + return x; + return unimap[x]; + } + + private void _SetCursor(int row,int col) { + int maxr = getRows(); + int tm = getTopMargin(); + + R = (row<0)?0:row; + C = (col<0)?0:col; + + if (!moveoutsidemargins) { + R += getTopMargin(); + maxr = getBottomMargin(); + } + if (R>maxr) R = maxr; + } + + private void putChar(char c, boolean doshowcursor) { + Dimension size; + int rows = getRows(); //statusline + int columns = getColumns(); + int tm = getTopMargin(); + int bm = getBottomMargin(); + String tosend; + byte msg[]; + + if (debug>4) System.out.println("putChar("+c+" ["+((int)c)+"]) at R="+R+" , C="+C+", columns="+columns+", rows="+rows); + markLine(R,1); + if (c>255) { + if (debug>0) + System.out.println("char > 255:"+((int)c)); + return; + } + switch (term_state) { + case TSTATE_DATA: + /* FIXME: we shouldn't use chars with bit 8 set if ibmcharset. + * probably... but some BBS do anyway... + */ + if (!useibmcharset) { + boolean doneflag = true; + switch (c) { + case OSC: + osc=""; + term_state = TSTATE_OSC; + break; + case RI: + if (R>tm) + R--; + else + insertLine(R,1,SCROLL_DOWN); + if (debug>1) + System.out.println("RI"); + break; + case IND: + if (R == tm - 1 || R == bm || R == rows - 1) // Ray: not bottom margin - 1 + insertLine(R,1,SCROLL_UP); + else + R++; + if (debug>1) + System.out.println("IND (at "+R+" )"); + break; + case NEL: + if (R == tm - 1 || R == bm || R == rows - 1) // Ray: not bottom margin - 1 + insertLine(R,1,SCROLL_UP); + else + R++; + C=0; + if (debug>1) + System.out.println("NEL (at "+R+" )"); + break; + case HTS: + Tabs[C] = 1; + if (debug>1) + System.out.println("HTS"); + break; + case DCS: + dcs=""; + term_state = TSTATE_DCS; + break; + default: + doneflag = false; + break; + } + if (doneflag) break; + } + switch (c) { + case CSI: // should be in the 8bit section, but some BBS use this + term_state = TSTATE_DCEQ; + break; + case ESC: + term_state = TSTATE_ESC; + lastwaslf=0; + break; + case '\b': + C--; + if (C<0) + C=0; + lastwaslf = 0; + break; + case '\t': + if (insertmode == 1) { + int nr,newc; + + newc = C; + do { + insertChar(C,R,' ',attributes); + newc++; + } while (newc3) + System.out.println("R= "+R+", bm "+bm+", tm="+tm+", rows="+rows); + if (!vms) + { + if (lastwaslf!=0 && lastwaslf!=c) // Ray: I do not understand this logic. + break; + lastwaslf=c; + /*C = 0;*/ + } + // note: we do not scroll at the topmargin! only at the bottommargin + // of the scrollregion and at the bottom. + if ( R == bm || R >= rows - 1) + insertLine(R,1); + else + R++; + break; + case '\016': + /* ^N, Shift out - Put G1 into GL */ + gl = 1; + break; + case '\017': + /* ^O, Shift in - Put G0 into GL */ + gl = 0; + break; + default: + lastwaslf=0; + if (c<32) { + if (c!=0) + if (debug>0) + System.out.println("TSTATE_DATA char: "+((int)c)); + break; + } + if(C >= columns) { + if(R < rows - 1) + R++; + else + insertLine(R,SCROLL_UP); + C = 0; + } + + // Mapping if DEC Special is chosen charset + if ( gx[gl] == '0' ) { + if ( c >= '\u005f' && c <= '\u007e' ) { + if (debug>3) + System.out.print("Mapping "+c+" (index "+((short)c-0x5f)+" to "); + c = DECSPECIAL[(short)c - 0x5f]; + if (debug>3) + System.out.println(c+" ("+(int)c+")"); + } + } + /* + if ( gx[gr] == '0' ) { + if ( c >= '\u00bf' && c <= '\u00fe' ) { + if (debug>2) + System.out.print("Mapping "+c); + c = DECSPECIAL[(short)c - 0xbf]; + if (debug>2) + System.out.println("to "+c); + } + } + */ + if (useibmcharset) + c = map_cp850_unicode(c); + + /*if(true || (statusmode == 0)) { */ + if (debug>4) System.out.println("output "+c+" at "+C+","+R); + if (insertmode==1) { + insertChar(C, R, c, attributes); + } else { + putChar(C, R, c, attributes); + } + /* + } else { + if (insertmode==1) { + insertChar(C, rows, c, attributes); + } else { + putChar(C, rows, c, attributes); + } + } + */ + C++; + break; + } /* switch(c) */ + break; + case TSTATE_OSC: + if ((c<0x20) && (c!=ESC)) {// NP - No printing character + handle_osc(osc); + term_state = TSTATE_DATA; + break; + } + //but check for vt102 ESC \ + if (c=='\\' && osc.charAt(osc.length()-1)==ESC) { + handle_osc(osc); + term_state = TSTATE_DATA; + break; + } + osc = osc + c; + break; + case TSTATE_ESC: + switch (c) { + case '#': + term_state = TSTATE_ESCSQUARE; + break; + case 'c': + /* Hard terminal reset */ + /*FIXME:*/ + term_state = TSTATE_DATA; + break; + case '[': + term_state = TSTATE_CSI; + DCEvar = 0; + DCEvars[0] = 0; + DCEvars[1] = 0; + DCEvars[2] = 0; + DCEvars[3] = 0; + break; + case ']': + osc=""; + term_state = TSTATE_OSC; + break; + case 'P': + dcs=""; + term_state = TSTATE_DCS; + break; + case 'E': + if (R == tm - 1 || R == bm || R == rows - 1) // Ray: not bottom margin - 1 + insertLine(R,1,SCROLL_UP); + else + R++; + C=0; + if (debug>1) + System.out.println("ESC E (at "+R+")"); + term_state = TSTATE_DATA; + break; + case 'D': + if (R == tm - 1 || R == bm || R == rows - 1) + insertLine(R,1,SCROLL_UP); + else + R++; + if (debug>1) + System.out.println("ESC D (at "+R+" )"); + term_state = TSTATE_DATA; + break; + case 'M': // IL + if ((R>=tm) && (R<=bm)) // in scrolregion + insertLine(R,1,SCROLL_DOWN); + /* else do nothing ; */ + if (debug>1) + System.out.println("ESC M "); + term_state = TSTATE_DATA; + break; + case 'H': + if (debug>1) + System.out.println("ESC H at "+C); + /* right border probably ...*/ + if (C>=columns) + C=columns-1; + Tabs[C] = 1; + term_state = TSTATE_DATA; + break; + case '=': + /*application keypad*/ + if (debug>0) + System.out.println("ESC ="); + term_state = TSTATE_DATA; + break; + case '>': + /*normal keypad*/ + if (debug>0) + System.out.println("ESC >"); + term_state = TSTATE_DATA; + break; + case '7': + /*save cursor */ + Sc = C; + Sr = R; + Sa = attributes; + if (debug>1) + System.out.println("ESC 7"); + term_state = TSTATE_DATA; + break; + case '8': + /*restore cursor */ + C = Sc; + R = Sr; + attributes = Sa; + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC 7"); + break; + case '(': + /* Designate G0 Character set (ISO 2022) */ + term_state = TSTATE_SETG0; + break; + case ')': + /* Designate G0 character set (ISO 2022) */ + term_state = TSTATE_SETG1; + break; + case '*': + /* Designate G1 Character set (ISO 2022) */ + term_state = TSTATE_SETG2; + break; + case '+': + /* Designate G1 Character set (ISO 2022) */ + term_state = TSTATE_SETG3; + break; + case '~': + /* Locking Shift 1, right */ + term_state = TSTATE_DATA; + gr = 1; + break; + case 'n': + /* Locking Shift 2 */ + term_state = TSTATE_DATA; + gl = 2; + break; + case '}': + /* Locking Shift 2, right */ + term_state = TSTATE_DATA; + gr = 2; + break; + case 'o': + /* Locking Shift 3 */ + term_state = TSTATE_DATA; + gl = 3; + break; + case '|': + /* Locking Shift 3, right */ + term_state = TSTATE_DATA; + gr = 3; + break; + default: + System.out.println("ESC unknown letter: ("+((int)c)+")"); + term_state = TSTATE_DATA; + break; + } + break; + case TSTATE_SETG0: + if(c!='0' && c!='A' && c!='B') + System.out.println("ESC ( : G0 char set? ("+((int)c)+")"); + else { + if (debug>2) System.out.println("ESC ( : G0 char set ("+c+" "+((int)c)+")"); + gx[0] = c; + } + term_state = TSTATE_DATA; + break; + case TSTATE_SETG1: + if(c!='0' && c!='A' && c!='B') + System.out.println("ESC ) :G1 char set? ("+((int)c)+")"); + else { + if (debug>2) System.out.println("ESC ) :G1 char set ("+c+" "+((int)c)+")"); + gx[1] = c; + } + term_state = TSTATE_DATA; + break; + case TSTATE_SETG2: + if(c!='0' && c!='A' && c!='B') + System.out.println("ESC*:G2 char set? ("+((int)c)+")"); + else { + if (debug>2) System.out.println("ESC*:G2 char set ("+c+" "+((int)c)+")"); + gx[2] = c; + } + term_state = TSTATE_DATA; + break; + case TSTATE_SETG3: + if(c!='0' && c!='A' && c!='B') + System.out.println("ESC+:G3 char set? ("+((int)c)+")"); + else { + if (debug>2) System.out.println("ESC+:G3 char set ("+c+" "+((int)c)+")"); + gx[3] = c; + } + term_state = TSTATE_DATA; + break; + case TSTATE_ESCSQUARE: + switch (c) { + case '8': + for (int i=0;i1) + System.out.println("ESC [ ? "+DCEvars[0]+" r"); + /* DEC Mode reset */ + switch (DCEvars[0]){ + case 3: /* 80 columns*/ + size = getSize(); + setScreenSize(80,rows); + break; + case 4: /* scrolling mode, smooth */ + break; + case 5: /* light background */ + break; + case 6: /* move inside margins ? */ + moveoutsidemargins = true; + break; + case 12:/* local echo off */ + break; + } + term_state = TSTATE_DATA; + break; + case 'h': // DECSET + if (debug>0) + System.out.println("ESC [ ? "+DCEvars[0]+" h"); + /* DEC Mode set */ + switch (DCEvars[0]){ + case 1: /* Application cursor keys */ + KeyUp = "\u001bOA"; + KeyDown = "\u001bOB"; + KeyRight= "\u001bOC"; + KeyLeft = "\u001bOD"; + break; + case 3: /* 132 columns*/ + size = getSize(); + setScreenSize(132,rows); + break; + case 4: /* scrolling mode, smooth */ + break; + case 5: /* light background */ + break; + case 6: /* move inside margins ? */ + moveoutsidemargins = false; + break; + case 12:/* local echo off */ + break; + } + term_state = TSTATE_DATA; + break; + case 'l': //DECRST + /* DEC Mode reset */ + if (debug>0) + System.out.println("ESC [ ? "+DCEvars[0]+" l"); + switch (DCEvars[0]){ + case 1: /* Application cursor keys */ + KeyUp = "\u001b[A"; + KeyDown = "\u001b[B"; + KeyRight= "\u001b[C"; + KeyLeft = "\u001b[D"; + break; + case 3: /* 80 columns*/ + size = getSize(); + setScreenSize(80,rows); + break; + case 4: /* scrolling mode, jump */ + break; + case 5: /* dark background */ + break; + case 6: /* move outside margins ? */ + moveoutsidemargins = true; + break; + case 12:/* local echo on */ + break; + } + term_state = TSTATE_DATA; + break; + case ';': + DCEvar++; + DCEvars[DCEvar] = 0; + break; + case 'n': + if (debug>0) + System.out.println("ESC [ ? "+DCEvars[0]+" n"); + switch (DCEvars[0]) { + case 15: + /* printer? no printer. */ + write(((char)ESC)+"[?13n"); + System.out.println("ESC[5n"); + break; + default:break; + } + term_state = TSTATE_DATA; + break; + default: + if (debug>0) + System.out.println("ESC [ ? "+DCEvars[0]+" "+c); + term_state = TSTATE_DATA; + break; + } + break; + case TSTATE_CSI_DOLLAR: + switch (c) { + case '}': + System.out.println("Active Status Display now "+DCEvars[0]); + statusmode = DCEvars[0]; + break; + /* bad documentation? + case '-': + System.out.println("Set Status Display now "+DCEvars[0]); + break; + */ + case '~': + System.out.println("Status Line mode now "+DCEvars[0]); + break; + default: + System.out.println("UNKNOWN Status Display code "+c+", with Pn="+DCEvars[0]); + break; + } + term_state = TSTATE_DATA; + break; + case TSTATE_CSI: + switch (c) { + case '$': + term_state=TSTATE_CSI_DOLLAR; + break; + case '?': + DCEvar=0; + DCEvars[0]=0; + term_state=TSTATE_DCEQ; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + DCEvars[DCEvar]=DCEvars[DCEvar]*10+((int)c)-48; + break; + case ';': + DCEvar++; + DCEvars[DCEvar] = 0; + break; + case 'c':/* send primary device attributes */ + /* send (ESC[?61c) */ + write(((char)ESC)+"[?1;2c"); + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" c"); + break; + case 'q': + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" q"); + term_state = TSTATE_DATA; + break; + case 'g': + /* used for tabsets */ + switch (DCEvars[0]){ + case 3:/* clear them */ + int nw = getColumns(); + Tabs = new byte[nw]; + break; + case 0: + Tabs[C] = 0; + break; + } + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" g"); + term_state = TSTATE_DATA; + break; + case 'h': + switch (DCEvars[0]) { + case 4: + insertmode = 1; + break; + case 20: + sendcrlf = true; + break; + default: + System.out.println("unsupported: ESC [ "+DCEvars[0]+" h"); + break; + } + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" h"); + break; + case 'l': + switch (DCEvars[0]) { + case 4: + insertmode = 0; + break; + case 20: + sendcrlf = false; + break; + } + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" l"); + break; + case 'A': // CUU + { + int limit; + /* FIXME: xterm only cares about 0 and topmargin */ + if (R > bm) + limit = bm+1; + else if (R >= tm) { + limit = tm; + } else + limit = 0; + if (DCEvars[0]==0) + R--; + else + R-=DCEvars[0]; + if (R < limit) + R = limit; + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" A"); + break; + } + case 'B': // CUD + /* cursor down n (1) times */ + { + int limit; + if (R < tm) + limit = tm-1; + else if (R <= bm) { + limit = bm; + } else + limit = rows - 1; + if (DCEvars[0]==0) + R++; + else + R+=DCEvars[0]; + if (R > limit) + R = limit; + else { + if (debug>2) System.out.println("Not limited."); + } + if (debug>2) System.out.println("to: " + R); + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" B (at C="+C+")"); + break; + } + case 'C': + if (DCEvars[0]==0) + C++; + else + C+=DCEvars[0]; + if (C>columns-1) + C=columns-1; + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" C"); + break; + case 'd': // CVA + R = DCEvars[0]; + System.out.println("ESC [ "+DCEvars[0]+" d"); + term_state = TSTATE_DATA; + break; + case 'D': + if (DCEvars[0]==0) + C--; + else + C-=DCEvars[0]; + if (C<0) C=0; + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" D"); + break; + case 'r': // DECSTBM + if (DCEvar>0) // Ray: Any argument is optional + { + R = DCEvars[1]-1; + if (R < 0) + R = rows-1; + else if (R >= rows) { + R = rows - 1; + } + } else + R = rows - 1; + setBottomMargin(DCEvars[1]-1); + if (R >= DCEvars[0]) + { + R = DCEvars[0]-1; + if (R < 0) + R = 0; + } + setTopMargin(DCEvars[0]-1); + _SetCursor(0,0); + if (debug>1) + System.out.println("ESC ["+DCEvars[0]+" ; "+DCEvars[1]+" r"); + term_state = TSTATE_DATA; + break; + case 'G': /* CUP / cursor absolute column */ + C = DCEvars[0]; + System.out.println("ESC [ "+DCEvars[0]+" G"); + term_state = TSTATE_DATA; + break; + case 'H': /* CUP / cursor position */ + /* gets 2 arguments */ + _SetCursor(DCEvars[0]-1,DCEvars[1]-1); + term_state = TSTATE_DATA; + if (debug>2) { + System.out.println("ESC [ "+DCEvars[0]+";"+DCEvars[1]+" H, moveoutsidemargins "+moveoutsidemargins); + System.out.println(" -> R now "+R+", C now "+C); + } + break; + case 'f': /* move cursor 2 */ + /* gets 2 arguments */ + R = DCEvars[0]-1; + C = DCEvars[1]-1; + if (C<0) C=0; + if (R<0) R=0; + term_state = TSTATE_DATA; + if (debug>2) + System.out.println("ESC [ "+DCEvars[0]+";"+DCEvars[1]+" f"); + break; + case 'L': + /* insert n lines */ + if (DCEvars[0]==0) + insertLine(R,SCROLL_DOWN); + else + insertLine(R,DCEvars[0],SCROLL_DOWN); + term_state = TSTATE_DATA; + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" L (at R "+R+")"); + break; + case 'M': + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+"M at R="+R); + if (DCEvars[0]==0) + deleteLine(R); + else + for (int i=0;i1) + System.out.println("ESC [ "+DCEvars[0]+" K"); + /* clear in line */ + switch (DCEvars[0]) { + case 0:/*clear to right*/ + if (C0) + deleteArea(0,R,C,1); // Ray: Should at least include character before this one, not C-1 + break; + case 2:/*clear whole line */ + deleteArea(0,R,columns,1); + break; + } + term_state = TSTATE_DATA; + break; + case 'J': + /* clear below current line */ + switch (DCEvars[0]) { + case 0: + if (R0) + deleteArea(0,0,columns,R-1); + if (C>0) + deleteArea(0,R,C,1); // Ray: Should at least include character before this one, not C-1 + break; + case 2: + deleteArea(0,0,columns,rows); + break; + } + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" J"); + term_state = TSTATE_DATA; + break; + case '@': + if (debug>1) + System.out.println("ESC [ "+DCEvars[0]+" @"); + for (int i=0;i1) + System.out.println("ESC [ "+DCEvars[0]+" P, C="+C+",R="+R); + if (DCEvars[0]==0) DCEvars[0]=1; + for (int i=0;i 1) + System.out.println("ESC[5n"); + break; + case 6: + write(((char)ESC)+"["+R+";"+C+"R"); + if(debug > 1) + System.out.println("ESC[6n"); + break; + default: + if (debug>0) + System.out.println("ESC [ "+DCEvars[0]+" n??"); + break; + } + term_state = TSTATE_DATA; + break; + case 'm': /* attributes as color, bold , blink,*/ + if (debug>3) + System.out.print("ESC [ "); + if (DCEvar == 0 && DCEvars[0] == 0) + attributes = 0; + for (i=0;i<=DCEvar;i++) { + switch (DCEvars[i]) { + case 0: + if (DCEvar>0) + attributes =0; + break; + case 4: + attributes |= UNDERLINE; + break; + case 1: + attributes |= BOLD; + break; + case 7: + attributes |= INVERT; + break; + case 5: /* blink on */ + break; + case 25: /* blinking off */ + break; + case 27: + attributes &= ~INVERT; + break; + case 24: + attributes &= ~UNDERLINE; + break; + case 22: + attributes &= ~BOLD; + break; + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + attributes &= ~(0xf<<3); + attributes |= ((DCEvars[i]-30)+1)<<3; + break; + case 39: + attributes &= ~(0xf<<3); + break; + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + attributes &= ~(0xf<<7); + attributes |= ((DCEvars[i]-40)+1)<<7; + break; + case 49: + attributes &= ~(0xf<<7); + break; + + default: + System.out.println("ESC [ "+DCEvars[i]+" m unknown..."); + break; + } + if (debug>3) + System.out.print(""+DCEvars[i]+";"); + } + if (debug>3) + System.out.print(" (attributes = "+attributes+")m \n"); + term_state = TSTATE_DATA; + break; + default: + if (debug>0) + System.out.println("ESC [ unknown letter:"+c+" ("+((int)c)+")"); + term_state = TSTATE_DATA; + break; + } + break; + default: + term_state = TSTATE_DATA; + break; + } + if (C > columns) C = columns; + if (R > rows) R = rows; + if (C < 0) C = 0; + if (R < 0) R = 0; + if (doshowcursor) + setCursorPosition(C, R); + markLine(R,1); + } +}