-rw-r--r-- | noncore/apps/opie-console/emulation_layer.cpp | 372 | ||||
-rw-r--r-- | noncore/apps/opie-console/emulation_layer.cpp~ | 373 | ||||
-rw-r--r-- | noncore/apps/opie-console/emulation_layer.h | 146 | ||||
-rw-r--r-- | noncore/apps/opie-console/emulation_layer.o | bin | 0 -> 13224 bytes | |||
-rw-r--r-- | noncore/apps/opie-console/history.cpp | 218 | ||||
-rw-r--r-- | noncore/apps/opie-console/history.h | 82 | ||||
-rw-r--r-- | noncore/apps/opie-console/history.o | bin | 0 -> 6468 bytes | |||
-rw-r--r-- | noncore/apps/opie-console/keytrans.cpp | 706 | ||||
-rw-r--r-- | noncore/apps/opie-console/keytrans.h | 93 | ||||
-rw-r--r-- | noncore/apps/opie-console/keytrans.o | bin | 0 -> 34264 bytes | |||
-rw-r--r-- | noncore/apps/opie-console/screen.cpp | 1197 | ||||
-rw-r--r-- | noncore/apps/opie-console/screen.h | 259 | ||||
-rw-r--r-- | noncore/apps/opie-console/screen.o | bin | 0 -> 15864 bytes | |||
-rw-r--r-- | noncore/apps/opie-console/vt102emulation.cpp | 1029 | ||||
-rw-r--r-- | noncore/apps/opie-console/vt102emulation.h | 153 | ||||
-rw-r--r-- | noncore/apps/opie-console/vt102emulation.o | bin | 0 -> 33320 bytes |
16 files changed, 4628 insertions, 0 deletions
diff --git a/noncore/apps/opie-console/emulation_layer.cpp b/noncore/apps/opie-console/emulation_layer.cpp new file mode 100644 index 0000000..6c420e0 --- a/dev/null +++ b/noncore/apps/opie-console/emulation_layer.cpp @@ -0,0 +1,372 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [emulation_layer.cpp] Terminal Emulation Decoder */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Modified to suit opie-console */ +/* */ +/* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \class EmulationLayer + + \brief Mediator between Widget and Screen. + + This class is responsible to scan the escapes sequences of the terminal + emulation and to map it to their corresponding semantic complements. + Thus this module knows mainly about decoding escapes sequences and + is a stateless device w.r.t. the semantics. + + It is also responsible to refresh the Widget by certain rules. + + \sa Widget \sa Screen + + \par A note on refreshing + + Although the modifications to the current screen image could immediately + be propagated via `Widget' to the graphical surface, we have chosen + another way here. + + The reason for doing so is twofold. + + First, experiments show that directly displaying the operation results + in slowing down the overall performance of emulations. Displaying + individual characters using X11 creates a lot of overhead. + + Second, by using the following refreshing method, the screen operations + can be completely separated from the displaying. This greatly simplifies + the programmer's task of coding and maintaining the screen operations, + since one need not worry about differential modifications on the + display affecting the operation of concern. + + We use a refreshing algorithm here that has been adoped from rxvt/kvt. + + By this, refreshing is driven by a timer, which is (re)started whenever + a new bunch of data to be interpreted by the emulation arives at `onRcvBlock'. + As soon as no more data arrive for `BULK_TIMEOUT' milliseconds, we trigger + refresh. This rule suits both bulk display operation as done by curses as + well as individual characters typed. + (BULK_TIMEOUT < 1000 / max characters received from keyboard per second). + + Additionally, we trigger refreshing by newlines comming in to make visual + snapshots of lists as produced by `cat', `ls' and likely programs, thereby + producing the illusion of a permanent and immediate display operation. + + As a sort of catch-all needed for cases where none of the above + conditions catch, the screen refresh is also triggered by a count + of incoming bulks (`bulk_incnt'). +*/ + +/* FIXME + - evtl. the bulk operations could be made more transparent. +*/ + +#include "emulation_layer.h" +#include "widget.h" +#include "screen.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <qkeycode.h> + + +/* ------------------------------------------------------------------------- */ +/* */ +/* EmulationLayer */ +/* */ +/* ------------------------------------------------------------------------- */ + +#define CNTL(c) ((c)-'@') + +/*! +*/ + +EmulationLayer::EmulationLayer(Widget* gui) +: decoder((QTextDecoder*)NULL) +{ + this->gui = gui; + + screen[0] = new Screen(gui->Lines(),gui->Columns()); + screen[1] = new Screen(gui->Lines(),gui->Columns()); + scr = screen[0]; + + bulk_nlcnt = 0; // reset bulk newline counter + bulk_incnt = 0; // reset bulk counter + connected = FALSE; + + QObject::connect(&bulk_timer, SIGNAL(timeout()), this, SLOT(showBulk()) ); + QObject::connect(gui,SIGNAL(changedImageSizeSignal(int,int)), + this,SLOT(onImageSizeChange(int,int))); + QObject::connect(gui,SIGNAL(changedHistoryCursor(int)), + this,SLOT(onHistoryCursorChange(int))); + QObject::connect(gui,SIGNAL(keyPressedSignal(QKeyEvent*)), + this,SLOT(onKeyPress(QKeyEvent*))); + QObject::connect(gui,SIGNAL(beginSelectionSignal(const int,const int)), + this,SLOT(onSelectionBegin(const int,const int)) ); + QObject::connect(gui,SIGNAL(extendSelectionSignal(const int,const int)), + this,SLOT(onSelectionExtend(const int,const int)) ); + QObject::connect(gui,SIGNAL(endSelectionSignal(const BOOL)), + this,SLOT(setSelection(const BOOL)) ); + QObject::connect(gui,SIGNAL(clearSelectionSignal()), + this,SLOT(clearSelection()) ); +} + +/*! +*/ + +EmulationLayer::~EmulationLayer() +{ + delete screen[0]; + delete screen[1]; + bulk_timer.stop(); +} + +/*! change between primary and alternate screen +*/ + +void EmulationLayer::setScreen(int n) +{ + scr = screen[n&1]; +} + +void EmulationLayer::setHistory(bool on) +{ + screen[0]->setScroll(on); + if (!connected) return; + showBulk(); +} + +bool EmulationLayer::history() +{ + return screen[0]->hasScroll(); +} + +void EmulationLayer::setCodec(int c) +{ + //FIXME: check whether we have to free codec + codec = c ? QTextCodec::codecForName("utf8") + : QTextCodec::codecForLocale(); + if (decoder) delete decoder; + decoder = codec->makeDecoder(); +} + +void EmulationLayer::setKeytrans(int no) +{ + keytrans = KeyTrans::find(no); +} + +void EmulationLayer::setKeytrans(const char * no) +{ + keytrans = KeyTrans::find(no); +} + +// Interpreting Codes --------------------------------------------------------- + +/* + This section deals with decoding the incoming character stream. + Decoding means here, that the stream is first seperated into `tokens' + which are then mapped to a `meaning' provided as operations by the + `Screen' class. +*/ + +/*! +*/ + +void EmulationLayer::onRcvChar(int c) +// process application unicode input to terminal +// this is a trivial scanner +{ + c &= 0xff; + switch (c) + { + case '\b' : scr->BackSpace(); break; + case '\t' : scr->Tabulate(); break; + case '\n' : scr->NewLine(); break; + case '\r' : scr->Return(); break; + case 0x07 : gui->Bell(); break; + default : scr->ShowCharacter(c); break; + }; +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Keyboard Handling */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! +*/ + +void EmulationLayer::onKeyPress( QKeyEvent* ev ) +{ + if (!connected) return; // someone else gets the keys + if (scr->getHistCursor() != scr->getHistLines()); + scr->setHistCursor(scr->getHistLines()); + if (!ev->text().isEmpty()) + { // A block of text + // Note that the text is proper unicode. + // We should do a conversion here, but since this + // routine will never be used, we simply emit plain ascii. + sendString( ev->text().ascii() ); //,ev->text().length()); + } + else if (ev->ascii()>0) + { + QByteArray c = QByteArray( 1 ); + c.at( 0 ) = ev->ascii(); + // ibot: qbytearray is emited not char* + emit sndBlock( (QByteArray) c ); + } +} + +// Unblocking, Byte to Unicode translation --------------------------------- -- + +/* + We are doing code conversion from locale to unicode first. +*/ + +void EmulationLayer::onRcvBlock(const QByteArray &s ) +{ + bulkStart(); + bulk_incnt += 1; + for (int i = 0; i < s.size(); i++) + { + //TODO: ibot: maybe decoding qbytearray to unicode in io_layer? + QString result = decoder->toUnicode(&s[i],1); + int reslen = result.length(); + for (int j = 0; j < reslen; j++) + onRcvChar(result[j].unicode()); + if (s[i] == '\n') bulkNewline(); + } + bulkEnd(); +} + +// Selection --------------------------------------------------------------- -- + +void EmulationLayer::onSelectionBegin(const int x, const int y) { + if (!connected) return; + scr->setSelBeginXY(x,y); + showBulk(); +} + +void EmulationLayer::onSelectionExtend(const int x, const int y) { + if (!connected) return; + scr->setSelExtentXY(x,y); + showBulk(); +} + +void EmulationLayer::setSelection(const BOOL preserve_line_breaks) { + if (!connected) return; + QString t = scr->getSelText(preserve_line_breaks); + if (!t.isNull()) gui->setSelection(t); +} + +void EmulationLayer::clearSelection() { + if (!connected) return; + scr->clearSelection(); + showBulk(); +} + +// Refreshing -------------------------------------------------------------- -- + +#define BULK_TIMEOUT 20 + +/*! + called when \n comes in. Evtl. triggers showBulk at endBulk +*/ + +void EmulationLayer::bulkNewline() +{ + bulk_nlcnt += 1; + bulk_incnt = 0; // reset bulk counter since `nl' rule applies +} + +/*! +*/ + +void EmulationLayer::showBulk() +{ + bulk_nlcnt = 0; // reset bulk newline counter + bulk_incnt = 0; // reset bulk counter + if (connected) + { + Character* image = scr->getCookedImage(); // get the image + gui->setImage(image, + scr->getLines(), + scr->getColumns()); // actual refresh + free(image); + //FIXME: check that we do not trigger other draw event here. + gui->setScroll(scr->getHistCursor(),scr->getHistLines()); + } +} + +void EmulationLayer::bulkStart() +{ + if (bulk_timer.isActive()) bulk_timer.stop(); +} + +void EmulationLayer::bulkEnd() +{ + if ( bulk_nlcnt > gui->Lines() || bulk_incnt > 20 ) + showBulk(); // resets bulk_??cnt to 0, too. + else + bulk_timer.start(BULK_TIMEOUT,TRUE); +} + +void EmulationLayer::setConnect(bool c) +{ + connected = c; + if ( connected) + { + onImageSizeChange(gui->Lines(), gui->Columns()); + showBulk(); + } + else + { + scr->clearSelection(); + } +} + +// --------------------------------------------------------------------------- + +/*! triggered by image size change of the Widget `gui'. + + This event is simply propagated to the attached screens + and to the related serial line. +*/ + +void EmulationLayer::onImageSizeChange(int lines, int columns) +{ + if (!connected) return; + screen[0]->resizeImage(lines,columns); + screen[1]->resizeImage(lines,columns); + showBulk(); + emit ImageSizeChanged(lines,columns); // propagate event to serial line +} + +void EmulationLayer::onHistoryCursorChange(int cursor) +{ + if (!connected) return; + scr->setHistCursor(cursor); + showBulk(); +} + +void EmulationLayer::setColumns(int columns) +{ + //FIXME: this goes strange ways. + // Can we put this straight or explain it at least? + emit changeColumns(columns); +} diff --git a/noncore/apps/opie-console/emulation_layer.cpp~ b/noncore/apps/opie-console/emulation_layer.cpp~ new file mode 100644 index 0000000..e65fd4b --- a/dev/null +++ b/noncore/apps/opie-console/emulation_layer.cpp~ @@ -0,0 +1,373 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [TEmulation.cpp] Terminal Emulation Decoder */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* */ +/* Modified to suit opie-console */ +/* */ +/* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! \class TEmulation + + \brief Mediator between TEWidget and TEScreen. + + This class is responsible to scan the escapes sequences of the terminal + emulation and to map it to their corresponding semantic complements. + Thus this module knows mainly about decoding escapes sequences and + is a stateless device w.r.t. the semantics. + + It is also responsible to refresh the TEWidget by certain rules. + + \sa TEWidget \sa TEScreen + + \par A note on refreshing + + Although the modifications to the current screen image could immediately + be propagated via `TEWidget' to the graphical surface, we have chosen + another way here. + + The reason for doing so is twofold. + + First, experiments show that directly displaying the operation results + in slowing down the overall performance of emulations. Displaying + individual characters using X11 creates a lot of overhead. + + Second, by using the following refreshing method, the screen operations + can be completely separated from the displaying. This greatly simplifies + the programmer's task of coding and maintaining the screen operations, + since one need not worry about differential modifications on the + display affecting the operation of concern. + + We use a refreshing algorithm here that has been adoped from rxvt/kvt. + + By this, refreshing is driven by a timer, which is (re)started whenever + a new bunch of data to be interpreted by the emulation arives at `onRcvBlock'. + As soon as no more data arrive for `BULK_TIMEOUT' milliseconds, we trigger + refresh. This rule suits both bulk display operation as done by curses as + well as individual characters typed. + (BULK_TIMEOUT < 1000 / max characters received from keyboard per second). + + Additionally, we trigger refreshing by newlines comming in to make visual + snapshots of lists as produced by `cat', `ls' and likely programs, thereby + producing the illusion of a permanent and immediate display operation. + + As a sort of catch-all needed for cases where none of the above + conditions catch, the screen refresh is also triggered by a count + of incoming bulks (`bulk_incnt'). +*/ + +/* FIXME + - evtl. the bulk operations could be made more transparent. +*/ + +#include "emulation_layer.h" +#include "widget.h" +#include "TEScreen.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <qkeycode.h> + + +/* ------------------------------------------------------------------------- */ +/* */ +/* EmulationLayer */ +/* */ +/* ------------------------------------------------------------------------- */ + +#define CNTL(c) ((c)-'@') + +/*! +*/ + +EmulationLayer::EmulationLayer(TEWidget* gui) +: decoder((QTextDecoder*)NULL) +{ + this->gui = gui; + + screen[0] = new TEScreen(gui->Lines(),gui->Columns()); + screen[1] = new TEScreen(gui->Lines(),gui->Columns()); + scr = screen[0]; + + bulk_nlcnt = 0; // reset bulk newline counter + bulk_incnt = 0; // reset bulk counter + connected = FALSE; + + QObject::connect(&bulk_timer, SIGNAL(timeout()), this, SLOT(showBulk()) ); + QObject::connect(gui,SIGNAL(changedImageSizeSignal(int,int)), + this,SLOT(onImageSizeChange(int,int))); + QObject::connect(gui,SIGNAL(changedHistoryCursor(int)), + this,SLOT(onHistoryCursorChange(int))); + QObject::connect(gui,SIGNAL(keyPressedSignal(QKeyEvent*)), + this,SLOT(onKeyPress(QKeyEvent*))); + QObject::connect(gui,SIGNAL(beginSelectionSignal(const int,const int)), + this,SLOT(onSelectionBegin(const int,const int)) ); + QObject::connect(gui,SIGNAL(extendSelectionSignal(const int,const int)), + this,SLOT(onSelectionExtend(const int,const int)) ); + QObject::connect(gui,SIGNAL(endSelectionSignal(const BOOL)), + this,SLOT(setSelection(const BOOL)) ); + QObject::connect(gui,SIGNAL(clearSelectionSignal()), + this,SLOT(clearSelection()) ); +} + +/*! +*/ + +EmulationLayer::~EmulationLayer() +{ + delete screen[0]; + delete screen[1]; + bulk_timer.stop(); +} + +/*! change between primary and alternate screen +*/ + +void EmulationLayer::setScreen(int n) +{ + scr = screen[n&1]; +} + +void EmulationLayer::setHistory(bool on) +{ + screen[0]->setScroll(on); + if (!connected) return; + showBulk(); +} + +bool EmulationLayer::history() +{ + return screen[0]->hasScroll(); +} + +void EmulationLayer::setCodec(int c) +{ + //FIXME: check whether we have to free codec + codec = c ? QTextCodec::codecForName("utf8") + : QTextCodec::codecForLocale(); + if (decoder) delete decoder; + decoder = codec->makeDecoder(); +} + +void EmulationLayer::setKeytrans(int no) +{ + keytrans = KeyTrans::find(no); +} + +void EmulationLayer::setKeytrans(const char * no) +{ + keytrans = KeyTrans::find(no); +} + +// Interpreting Codes --------------------------------------------------------- + +/* + This section deals with decoding the incoming character stream. + Decoding means here, that the stream is first seperated into `tokens' + which are then mapped to a `meaning' provided as operations by the + `Screen' class. +*/ + +/*! +*/ + +void EmulationLayer::onRcvChar(int c) +// process application unicode input to terminal +// this is a trivial scanner +{ + c &= 0xff; + switch (c) + { + case '\b' : scr->BackSpace(); break; + case '\t' : scr->Tabulate(); break; + case '\n' : scr->NewLine(); break; + case '\r' : scr->Return(); break; + case 0x07 : gui->Bell(); break; + default : scr->ShowCharacter(c); break; + }; +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Keyboard Handling */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! +*/ + +void EmulationLayer::onKeyPress( QKeyEvent* ev ) +{ + if (!connected) return; // someone else gets the keys + if (scr->getHistCursor() != scr->getHistLines()); + scr->setHistCursor(scr->getHistLines()); + if (!ev->text().isEmpty()) + { // A block of text + // Note that the text is proper unicode. + // We should do a conversion here, but since this + // routine will never be used, we simply emit plain ascii. + sendString( ev->text().ascii() ); //,ev->text().length()); + } + else if (ev->ascii()>0) + { + QByteArray c = QByteArray( 1 ); + c.at( 0 ) = ev->ascii(); + // ibot: qbytearray is emited not char* + emit sndBlock( (QByteArray) c ); + } +} + +// Unblocking, Byte to Unicode translation --------------------------------- -- + +/* + We are doing code conversion from locale to unicode first. +*/ + +void EmulationLayer::onRcvBlock(const QByteArray &s ) +{ + bulkStart(); + bulk_incnt += 1; + for (int i = 0; i < s.size(); i++) + { + //TODO: ibot: maybe decoding qbytearray to unicode in io_layer? + QString result = decoder->toUnicode(&s[i],1); + int reslen = result.length(); + for (int j = 0; j < reslen; j++) + onRcvChar(result[j].unicode()); + if (s[i] == '\n') bulkNewline(); + } + bulkEnd(); +} + +// Selection --------------------------------------------------------------- -- + +void EmulationLayer::onSelectionBegin(const int x, const int y) { + if (!connected) return; + scr->setSelBeginXY(x,y); + showBulk(); +} + +void EmulationLayer::onSelectionExtend(const int x, const int y) { + if (!connected) return; + scr->setSelExtentXY(x,y); + showBulk(); +} + +void EmulationLayer::setSelection(const BOOL preserve_line_breaks) { + if (!connected) return; + QString t = scr->getSelText(preserve_line_breaks); + if (!t.isNull()) gui->setSelection(t); +} + +void EmulationLayer::clearSelection() { + if (!connected) return; + scr->clearSelection(); + showBulk(); +} + +// Refreshing -------------------------------------------------------------- -- + +#define BULK_TIMEOUT 20 + +/*! + called when \n comes in. Evtl. triggers showBulk at endBulk +*/ + +void EmulationLayer::bulkNewline() +{ + bulk_nlcnt += 1; + bulk_incnt = 0; // reset bulk counter since `nl' rule applies +} + +/*! +*/ + +void EmulationLayer::showBulk() +{ + bulk_nlcnt = 0; // reset bulk newline counter + bulk_incnt = 0; // reset bulk counter + if (connected) + { + ca* image = scr->getCookedImage(); // get the image + gui->setImage(image, + scr->getLines(), + scr->getColumns()); // actual refresh + free(image); + //FIXME: check that we do not trigger other draw event here. + gui->setScroll(scr->getHistCursor(),scr->getHistLines()); + } +} + +void EmulationLayer::bulkStart() +{ + if (bulk_timer.isActive()) bulk_timer.stop(); +} + +void EmulationLayer::bulkEnd() +{ + if ( bulk_nlcnt > gui->Lines() || bulk_incnt > 20 ) + showBulk(); // resets bulk_??cnt to 0, too. + else + bulk_timer.start(BULK_TIMEOUT,TRUE); +} + +void EmulationLayer::setConnect(bool c) +{ + connected = c; + if ( connected) + { + onImageSizeChange(gui->Lines(), gui->Columns()); + showBulk(); + } + else + { + scr->clearSelection(); + } +} + +// --------------------------------------------------------------------------- + +/*! triggered by image size change of the TEWidget `gui'. + + This event is simply propagated to the attached screens + and to the related serial line. +*/ + +void EmulationLayer::onImageSizeChange(int lines, int columns) +{ + if (!connected) return; + screen[0]->resizeImage(lines,columns); + screen[1]->resizeImage(lines,columns); + showBulk(); + emit ImageSizeChanged(lines,columns); // propagate event to serial line +} + +void EmulationLayer::onHistoryCursorChange(int cursor) +{ + if (!connected) return; + scr->setHistCursor(cursor); + showBulk(); +} + +void EmulationLayer::setColumns(int columns) +{ + //FIXME: this goes strange ways. + // Can we put this straight or explain it at least? + emit changeColumns(columns); +} diff --git a/noncore/apps/opie-console/emulation_layer.h b/noncore/apps/opie-console/emulation_layer.h new file mode 100644 index 0000000..0f54331 --- a/dev/null +++ b/noncore/apps/opie-console/emulation_layer.h @@ -0,0 +1,146 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [emulation.h] Fundamental Terminal Emulation */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* */ +/* made to a layer between io_layer and widget */ +/* */ +/* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef EMULATION_LAYER_H +#define EMULATION_LAYER_H + +#include "widget.h" +#include "screen.h" +#include <qtimer.h> +#include <stdio.h> +#include <qtextcodec.h> +#include "keytrans.h" + +class EmulationLayer : public QObject +{ Q_OBJECT + +public: + + EmulationLayer(Widget* gui); + ~EmulationLayer(); + +public: + virtual void setHistory(bool on); + virtual bool history(); + +public slots: // signals incoming from Widget + + virtual void onImageSizeChange(int lines, int columns); + virtual void onHistoryCursorChange(int cursor); + virtual void onKeyPress(QKeyEvent*); + + virtual void clearSelection(); + virtual void onSelectionBegin(const int x, const int y); + virtual void onSelectionExtend(const int x, const int y); + virtual void setSelection(const BOOL preserve_line_breaks); + +public slots: // signals incoming from data source + + /** + * to be called, when new data arrives + */ + void onRcvBlock(const QByteArray&); + +signals: + + /** + * will send data, encoded to suit emulation + */ + void sndBlock(const QByteArray&); + + void ImageSizeChanged(int lines, int columns); + + void changeColumns(int columns); + + void changeTitle(int arg, const char* str); + + +public: + + /** + * process single char (decode) + */ + virtual void onRcvChar(int); + + virtual void setMode (int) = 0; + virtual void resetMode(int) = 0; + + /** + * @deprecated use qbytearray instead + */ + virtual void sendString(const char*) = 0; + + /** + * sends a string to IOLayer + * encodes to suit emulation before + */ + virtual void sendString(const QByteArray&) = 0; + + virtual void setConnect(bool r); + void setColumns(int columns); + + void setKeytrans(int no); + void setKeytrans(const char * no); + +protected: + + Widget* gui; + Screen* scr; // referes to one `screen' + Screen* screen[2]; // 0 = primary, 1 = alternate + void setScreen(int n); // set `scr' to `screen[n]' + + bool connected; // communicate with widget + + void setCodec(int c); // codec number, 0 = locale, 1=utf8 + + QTextCodec* codec; + QTextCodec* localeCodec; + QTextDecoder* decoder; + + KeyTrans* keytrans; + +// refreshing related material. +// this is localized in the class. +private slots: // triggered by timer + + void showBulk(); + +private: + + void bulkNewline(); + void bulkStart(); + void bulkEnd(); + +private: + + QTimer bulk_timer; + int bulk_nlcnt; // bulk newline counter + char* SelectedText; + int bulk_incnt; // bulk counter + + +}; + +#endif // ifndef EMULATION_H diff --git a/noncore/apps/opie-console/emulation_layer.o b/noncore/apps/opie-console/emulation_layer.o Binary files differnew file mode 100644 index 0000000..fe80bcb --- a/dev/null +++ b/noncore/apps/opie-console/emulation_layer.o diff --git a/noncore/apps/opie-console/history.cpp b/noncore/apps/opie-console/history.cpp new file mode 100644 index 0000000..3b82d16 --- a/dev/null +++ b/noncore/apps/opie-console/history.cpp @@ -0,0 +1,218 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [history.c] History Buffer */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported embedded-Konsole to opie-console */ +/* */ +/* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#include "history.h" +#include <stdlib.h> +#include <assert.h> +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +#define HERE printf("%s(%d): here\n",__FILE__,__LINE__) + +/* + An arbitrary long scroll. + + One can modify the scroll only by adding either cells + or newlines, but access it randomly. + + The model is that of an arbitrary wide typewriter scroll + in that the scroll is a serie of lines and each line is + a serie of cells with no overwriting permitted. + + The implementation provides arbitrary length and numbers + of cells and line/column indexed read access to the scroll + at constant costs. + +FIXME: some complain about the history buffer comsuming the + memory of their machines. This problem is critical + since the history does not behave gracefully in cases + where the memory is used up completely. + + I put in a workaround that should handle it problem + now gracefully. I'm not satisfied with the solution. + +FIXME: Terminating the history is not properly indicated + in the menu. We should throw a signal. + +FIXME: There is noticable decrease in speed, also. Perhaps, + there whole feature needs to be revisited therefore. + Disadvantage of a more elaborated, say block-oriented + scheme with wrap around would be it's complexity. +*/ + +//FIXME: tempory replacement for tmpfile +// this is here one for debugging purpose. + +//#define tmpfile xTmpFile + +FILE* xTmpFile() +{ + static int fid = 0; + char fname[80]; + sprintf(fname,"TmpFile.%d",fid++); + return fopen(fname,"w"); +} + + +// History Buffer /////////////////////////////////////////// + +/* + A Row(X) data type which allows adding elements to the end. +*/ + +HistoryBuffer::HistoryBuffer() +{ + ion = -1; + length = 0; +} + +HistoryBuffer::~HistoryBuffer() +{ + setScroll(FALSE); +} + +void HistoryBuffer::setScroll(bool on) +{ + if (on == hasScroll()) return; + + if (on) + { + assert( ion < 0 ); + assert( length == 0); + FILE* tmp = tmpfile(); if (!tmp) { perror("konsole: cannot open temp file.\n"); return; } + ion = dup(fileno(tmp)); if (ion<0) perror("konsole: cannot dup temp file.\n"); + fclose(tmp); + } + else + { + assert( ion >= 0 ); + close(ion); + ion = -1; + length = 0; + } +} + +bool HistoryBuffer::hasScroll() +{ + return ion >= 0; +} + +void HistoryBuffer::add(const unsigned char* bytes, int len) +{ int rc; + assert(hasScroll()); + rc = lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setScroll(FALSE); return; } + rc = write(ion,bytes,len); if (rc < 0) { perror("HistoryBuffer::add.write"); setScroll(FALSE); return; } + length += rc; +} + +void HistoryBuffer::get(unsigned char* bytes, int len, int loc) +{ int rc; + assert(hasScroll()); + if (loc < 0 || len < 0 || loc + len > length) + fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc); + rc = lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryBuffer::get.seek"); setScroll(FALSE); return; } + rc = read(ion,bytes,len); if (rc < 0) { perror("HistoryBuffer::get.read"); setScroll(FALSE); return; } +} + +int HistoryBuffer::len() +{ + return length; +} + +// History Scroll ////////////////////////////////////// + +/* + The history scroll makes a Row(Row(Cell)) from + two history buffers. The index buffer contains + start of line positions which refere to the cells + buffer. + + Note that index[0] addresses the second line + (line #1), while the first line (line #0) starts + at 0 in cells. +*/ + +HistoryScroll::HistoryScroll() +{ +} + +HistoryScroll::~HistoryScroll() +{ +} + +void HistoryScroll::setScroll(bool on) +{ + index.setScroll(on); + cells.setScroll(on); +} + +bool HistoryScroll::hasScroll() +{ + return index.hasScroll() && cells.hasScroll(); +} + +int HistoryScroll::getLines() +{ + if (!hasScroll()) return 0; + return index.len() / sizeof(int); +} + +int HistoryScroll::getLineLen(int lineno) +{ + if (!hasScroll()) return 0; + return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character); +} + +int HistoryScroll::startOfLine(int lineno) +{ + if (lineno <= 0) return 0; + if (!hasScroll()) return 0; + if (lineno <= getLines()) + { int res; + index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int)); + return res; + } + return cells.len(); +} + +void HistoryScroll::getCells(int lineno, int colno, int count, Character res[]) +{ + assert(hasScroll()); + cells.get((unsigned char*)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character)); +} + +void HistoryScroll::addCells(Character text[], int count) +{ + if (!hasScroll()) return; + cells.add((unsigned char*)text,count*sizeof(Character)); +} + +void HistoryScroll::addLine() +{ + if (!hasScroll()) return; + int locn = cells.len(); + index.add((unsigned char*)&locn,sizeof(int)); +} diff --git a/noncore/apps/opie-console/history.h b/noncore/apps/opie-console/history.h new file mode 100644 index 0000000..aa77ebb --- a/dev/null +++ b/noncore/apps/opie-console/history.h @@ -0,0 +1,82 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [history.h] History Buffer */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* ported embedded_konsole to opie-console */ +/* */ +/* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef HISTORY_H +#define HISTORY_H + +#include "common.h" + +/* + An extendable tmpfile(1) based buffer. +*/ +class HistoryBuffer +{ +public: + HistoryBuffer(); + ~HistoryBuffer(); + +public: + void setScroll(bool on); + bool hasScroll(); + +public: + void add(const unsigned char* bytes, int len); + void get(unsigned char* bytes, int len, int loc); + int len(); + +private: + int ion; + int length; +}; + +class HistoryScroll +{ +public: + HistoryScroll(); + ~HistoryScroll(); + +public: + void setScroll(bool on); + bool hasScroll(); + +public: // access to history + int getLines(); + int getLineLen(int lineno); + void getCells(int lineno, int colno, int count, Character res[]); + +public: // backward compatibility (obsolete) + Character getCell(int lineno, int colno) { Character res; getCells(lineno,colno,1,&res); return res; } + +public: // adding lines. + void addCells(Character a[], int count); + void addLine(); + +private: + int startOfLine(int lineno); + HistoryBuffer index; // lines Row(int) + HistoryBuffer cells; // text Row(Character) +}; + +#endif // HISTORY_H diff --git a/noncore/apps/opie-console/history.o b/noncore/apps/opie-console/history.o Binary files differnew file mode 100644 index 0000000..256d3a5 --- a/dev/null +++ b/noncore/apps/opie-console/history.o diff --git a/noncore/apps/opie-console/keytrans.cpp b/noncore/apps/opie-console/keytrans.cpp new file mode 100644 index 0000000..d569ae0 --- a/dev/null +++ b/noncore/apps/opie-console/keytrans.cpp @@ -0,0 +1,706 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [keytrans.C] Keyboard Translation */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/* + The keyboard translation table allows to configure konsoles behavior + on key strokes. + + FIXME: some bug crept in, disallowing '\0' to be emitted. +*/ + +#include "keytrans.h" + +#include <qpe/qpeapplication.h> + +#include <qnamespace.h> +#include <qbuffer.h> +#include <qobject.h> +#include <qdict.h> +#include <qintdict.h> +#include <qfile.h> +#include <qglobal.h> +#include <qdir.h> + +//#include <kstddirs.h> +//nclude <klocale.h> + +#include <stdio.h> + + +#undef USE_APPDATA_DIR + + +#define HERE printf("%s(%d): here\n",__FILE__,__LINE__) + +/* KeyEntry + + instances represent the individual assignments +*/ + +KeyTrans::KeyEntry::KeyEntry(int _ref, int _key, int _bits, int _mask, int _cmd, QString _txt) +: ref(_ref), key(_key), bits(_bits), mask(_mask), cmd(_cmd), txt(_txt) +{ +} + +KeyTrans::KeyEntry::~KeyEntry() +{ +} + +bool KeyTrans::KeyEntry::matches(int _key, int _bits, int _mask) +{ int m = mask & _mask; + return _key == key && (bits & m) == (_bits & m); +} + +QString KeyTrans::KeyEntry::text() +{ + return txt; +} + +/* KeyTrans + + combines the individual assignments to a proper map + Takes part in a collection themself. +*/ + +KeyTrans::KeyTrans() +{ + path = ""; + numb = 0; +} + +KeyTrans::~KeyTrans() +{ +} + +KeyTrans::KeyEntry* KeyTrans::addEntry(int ref, int key, int bits, int mask, int cmd, QString txt) +// returns conflicting entry +{ + for (QListIterator<KeyEntry> it(table); it.current(); ++it) + { + if (it.current()->matches(key,bits,mask)) + { + return it.current(); + } + } + table.append(new KeyEntry(ref,key,bits,mask,cmd,txt)); + return (KeyEntry*)NULL; +} + +bool KeyTrans::findEntry(int key, int bits, int* cmd, const char** txt, int* len) +{ + for (QListIterator<KeyEntry> it(table); it.current(); ++it) + if (it.current()->matches(key,bits,0xffff)) + { + *cmd = it.current()->cmd; + *txt = it.current()->txt.ascii(); + *len = it.current()->txt.length(); + return TRUE; + } + return FALSE; +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Scanner for keyboard configuration */ +/* */ +/* ------------------------------------------------------------------------- */ + +// regular tokenizer +/* Tokens + - Spaces + - Name (A-Za-z0-9)+ + - String + - Opr on of +-: +*/ + +#define SYMName 0 +#define SYMString 1 +#define SYMEol 2 +#define SYMEof 3 +#define SYMOpr 4 +#define SYMError 5 + +#define inRange(L,X,H) ((L <= X) && (X <= H)) +#define isNibble(X) (inRange('A',X,'F')||inRange('a',X,'f')||inRange('0',X,'9')) +#define convNibble(X) (inRange('0',X,'9')?X-'0':X+10-(inRange('A',X,'F')?'A':'a')) + +class KeytabReader +{ +public: + KeytabReader(QString p, QIODevice &d); +public: + void getCc(); + void getSymbol(); + void parseTo(KeyTrans* kt); + void ReportError(const char* msg); + void ReportToken(); // diagnostic +private: + int sym; + QString res; + int len; + int slinno; + int scolno; +private: + int cc; + int linno; + int colno; + QIODevice* buf; + QString path; +}; + + +KeytabReader::KeytabReader(QString p, QIODevice &d) +{ + path = p; + buf = &d; + cc = 0; +} + +void KeytabReader::getCc() +{ + if (cc == '\n') { linno += 1; colno = 0; } + if (cc < 0) return; + cc = buf->getch(); + colno += 1; +} + +void KeytabReader::getSymbol() +{ + res = ""; len = 0; sym = SYMError; + while (cc == ' ') getCc(); // skip spaces + if (cc == '#') // skip comment + { + while (cc != '\n' && cc > 0) getCc(); + } + slinno = linno; + scolno = colno; + if (cc <= 0) + { + sym = SYMEof; return; // eos + } + if (cc == '\n') + { + getCc(); + sym = SYMEol; return; // eol + } + if (inRange('A',cc,'Z')||inRange('a',cc,'z')||inRange('0',cc,'9')) + { + while (inRange('A',cc,'Z') || inRange('a',cc,'z') || inRange('0',cc,'9')) + { + res = res + (char)cc; + getCc(); + } + sym = SYMName; + return; + } + if (strchr("+-:",cc)) + { + res = ""; + res = res + (char)cc; + getCc(); + sym = SYMOpr; return; + } + if (cc == '"') + { + getCc(); + while (cc >= ' ' && cc != '"') + { int sc; + if (cc == '\\') // handle quotation + { + getCc(); + switch (cc) + { + case 'E' : sc = 27; getCc(); break; + case 'b' : sc = 8; getCc(); break; + case 'f' : sc = 12; getCc(); break; + case 't' : sc = 9; getCc(); break; + case 'r' : sc = 13; getCc(); break; + case 'n' : sc = 10; getCc(); break; + case '\\' : // fall thru + case '"' : sc = cc; getCc(); break; + case 'x' : getCc(); + sc = 0; + if (!isNibble(cc)) return; sc = 16*sc + convNibble(cc); getCc(); + if (!isNibble(cc)) return; sc = 16*sc + convNibble(cc); getCc(); + break; + default : return; + } + } + else + { + // regular char + sc = cc; getCc(); + } + res = res + (char)sc; + len = len + 1; + } + if (cc != '"') return; + getCc(); + sym = SYMString; return; + } +} + +void KeytabReader::ReportToken() // diagnostic +{ + printf("sym(%d): ",slinno); + switch(sym) + { + case SYMEol : printf("End of line"); break; + case SYMEof : printf("End of file"); break; + case SYMName : printf("Name: %s",res.latin1()); break; + case SYMOpr : printf("Opr : %s",res.latin1()); break; + case SYMString : printf("String len %d,%d ",res.length(),len); + for (unsigned i = 0; i < res.length(); i++) + printf(" %02x(%c)",res.latin1()[i],res.latin1()[i]>=' '?res.latin1()[i]:'?'); + break; + } + printf("\n"); +} + +void KeytabReader::ReportError(const char* msg) // diagnostic +{ + fprintf(stderr,"%s(%d,%d):error: %s.\n",path.ascii(),slinno,scolno,msg); +} + +// local symbol tables --------------------------------------------------------------------- + +class KeyTransSymbols +{ +public: + KeyTransSymbols(); +protected: + void defOprSyms(); + void defModSyms(); + void defKeySyms(); + void defKeySym(const char* key, int val); + void defOprSym(const char* key, int val); + void defModSym(const char* key, int val); +public: + QDict<QObject> keysyms; + QDict<QObject> modsyms; + QDict<QObject> oprsyms; +}; + +static KeyTransSymbols * syms = 0L; + +// parser ---------------------------------------------------------------------------------- +/* Syntax + - Line :: [KeyName { ("+" | "-") ModeName } ":" (String|CommandName)] "\n" + - Comment :: '#' (any but \n)* +*/ + +KeyTrans* KeyTrans::fromDevice(QString path, QIODevice &buf) +{ + KeyTrans* kt = new KeyTrans; + kt->path = path; + KeytabReader ktr(path,buf); ktr.parseTo(kt); + return kt; +} + + +#define assertSyntax(Cond,Message) if (!(Cond)) { ReportError(Message); goto ERROR; } + +void KeytabReader::parseTo(KeyTrans* kt) +{ + // Opening sequence + + buf->open(IO_ReadOnly); + getCc(); + linno = 1; + colno = 1; + getSymbol(); + +Loop: + // syntax: ["key" KeyName { ("+" | "-") ModeName } ":" String/CommandName] ["#" Comment] + if (sym == SYMName && !strcmp(res.latin1(),"keyboard")) + { + getSymbol(); assertSyntax(sym == SYMString, "Header expected") + kt->hdr = res.latin1(); + getSymbol(); assertSyntax(sym == SYMEol, "Text unexpected") + getSymbol(); // eoln + goto Loop; + } + if (sym == SYMName && !strcmp(res.latin1(),"key")) + { +//printf("line %3d: ",startofsym); + getSymbol(); assertSyntax(sym == SYMName, "Name expected") + assertSyntax(syms->keysyms[res], "Unknown key name") + int key = (int)syms->keysyms[res]-1; +//printf(" key %s (%04x)",res.latin1(),(int)syms->keysyms[res]-1); + getSymbol(); // + - : + int mode = 0; + int mask = 0; + while (sym == SYMOpr && (!strcmp(res.latin1(),"+") || !strcmp(res.latin1(),"-"))) + { + bool on = !strcmp(res.latin1(),"+"); + getSymbol(); + // mode name + assertSyntax(sym == SYMName, "Name expected") + assertSyntax(syms->modsyms[res], "Unknown mode name") + int bits = (int)syms->modsyms[res]-1; + if (mask & (1 << bits)) + { + fprintf(stderr,"%s(%d,%d): mode name used multible times.\n",path.ascii(),slinno,scolno); + } + else + { + mode |= (on << bits); + mask |= (1 << bits); + } +//printf(", mode %s(%d) %s",res.latin1(),(int)syms->modsyms[res]-1,on?"on":"off"); + getSymbol(); + } + assertSyntax(sym == SYMOpr && !strcmp(res.latin1(),":"), "':' expected") + getSymbol(); + // string or command + assertSyntax(sym == SYMName || sym == SYMString,"Command or string expected") + int cmd = 0; + if (sym == SYMName) + { + assertSyntax(syms->oprsyms[res], "Unknown operator name") + cmd = (int)syms->oprsyms[res]-1; +//printf(": do %s(%d)",res.latin1(),(int)syms->oprsyms[res]-1); + } + if (sym == SYMString) + { + cmd = CMD_send; +//printf(": send"); +//for (unsigned i = 0; i < res.length(); i++) +//printf(" %02x(%c)",res.latin1()[i],res.latin1()[i]>=' '?res.latin1()[i]:'?'); + } +//printf(". summary %04x,%02x,%02x,%d\n",key,mode,mask,cmd); + KeyTrans::KeyEntry* ke = kt->addEntry(slinno,key,mode,mask,cmd,res); + if (ke) + { + fprintf(stderr,"%s(%d): keystroke already assigned in line %d.\n",path.ascii(),slinno,ke->ref); + } + getSymbol(); + assertSyntax(sym == SYMEol, "Unexpected text") + goto Loop; + } + if (sym == SYMEol) + { + getSymbol(); + goto Loop; + } + + assertSyntax(sym == SYMEof, "Undecodable Line") + + buf->close(); + return; + +ERROR: + while (sym != SYMEol && sym != SYMEof) getSymbol(); // eoln + goto Loop; +} + + +KeyTrans* KeyTrans::defaultKeyTrans() +{ + QCString txt = +#include "default.keytab.h" + ; + QBuffer buf(txt); + return fromDevice("[buildin]",buf); +} + +KeyTrans* KeyTrans::fromFile(const char* path) +{ + QFile file(path); + return fromDevice(path,file); +} + +// local symbol tables --------------------------------------------------------------------- +// material needed for parsing the config file. +// This is incomplete work. + +void KeyTransSymbols::defKeySym(const char* key, int val) +{ + keysyms.insert(key,(QObject*)(val+1)); +} + +void KeyTransSymbols::defOprSym(const char* key, int val) +{ + oprsyms.insert(key,(QObject*)(val+1)); +} + +void KeyTransSymbols::defModSym(const char* key, int val) +{ + modsyms.insert(key,(QObject*)(val+1)); +} + +void KeyTransSymbols::defOprSyms() +{ + // Modifier + defOprSym("scrollLineUp", CMD_scrollLineUp ); + defOprSym("scrollLineDown",CMD_scrollLineDown); + defOprSym("scrollPageUp", CMD_scrollPageUp ); + defOprSym("scrollPageDown",CMD_scrollPageDown); + defOprSym("emitSelection", CMD_emitSelection ); + defOprSym("prevSession", CMD_prevSession ); + defOprSym("nextSession", CMD_nextSession ); +} + +void KeyTransSymbols::defModSyms() +{ + // Modifier + defModSym("Shift", BITS_Shift ); + defModSym("Control", BITS_Control ); + defModSym("Alt", BITS_Alt ); + // Modes + defModSym("BsHack", BITS_BsHack ); // deprecated + defModSym("Ansi", BITS_Ansi ); + defModSym("NewLine", BITS_NewLine ); + defModSym("AppCuKeys", BITS_AppCuKeys ); +} + +void KeyTransSymbols::defKeySyms() +{ + // Grey keys + defKeySym("Escape", Qt::Key_Escape ); + defKeySym("Tab", Qt::Key_Tab ); + defKeySym("Backtab", Qt::Key_Backtab ); + defKeySym("Backspace", Qt::Key_Backspace ); + defKeySym("Return", Qt::Key_Return ); + defKeySym("Enter", Qt::Key_Enter ); + defKeySym("Insert", Qt::Key_Insert ); + defKeySym("Delete", Qt::Key_Delete ); + defKeySym("Pause", Qt::Key_Pause ); + defKeySym("Print", Qt::Key_Print ); + defKeySym("SysReq", Qt::Key_SysReq ); + defKeySym("Home", Qt::Key_Home ); + defKeySym("End", Qt::Key_End ); + defKeySym("Left", Qt::Key_Left ); + defKeySym("Up", Qt::Key_Up ); + defKeySym("Right", Qt::Key_Right ); + defKeySym("Down", Qt::Key_Down ); + defKeySym("Prior", Qt::Key_Prior ); + defKeySym("Next", Qt::Key_Next ); + defKeySym("Shift", Qt::Key_Shift ); + defKeySym("Control", Qt::Key_Control ); + defKeySym("Meta", Qt::Key_Meta ); + defKeySym("Alt", Qt::Key_Alt ); + defKeySym("CapsLock", Qt::Key_CapsLock ); + defKeySym("NumLock", Qt::Key_NumLock ); + defKeySym("ScrollLock", Qt::Key_ScrollLock ); + defKeySym("F1", Qt::Key_F1 ); + defKeySym("F2", Qt::Key_F2 ); + defKeySym("F3", Qt::Key_F3 ); + defKeySym("F4", Qt::Key_F4 ); + defKeySym("F5", Qt::Key_F5 ); + defKeySym("F6", Qt::Key_F6 ); + defKeySym("F7", Qt::Key_F7 ); + defKeySym("F8", Qt::Key_F8 ); + defKeySym("F9", Qt::Key_F9 ); + defKeySym("F10", Qt::Key_F10 ); + defKeySym("F11", Qt::Key_F11 ); + defKeySym("F12", Qt::Key_F12 ); + defKeySym("F13", Qt::Key_F13 ); + defKeySym("F14", Qt::Key_F14 ); + defKeySym("F15", Qt::Key_F15 ); + defKeySym("F16", Qt::Key_F16 ); + defKeySym("F17", Qt::Key_F17 ); + defKeySym("F18", Qt::Key_F18 ); + defKeySym("F19", Qt::Key_F19 ); + defKeySym("F20", Qt::Key_F20 ); + defKeySym("F21", Qt::Key_F21 ); + defKeySym("F22", Qt::Key_F22 ); + defKeySym("F23", Qt::Key_F23 ); + defKeySym("F24", Qt::Key_F24 ); + defKeySym("F25", Qt::Key_F25 ); + defKeySym("F26", Qt::Key_F26 ); + defKeySym("F27", Qt::Key_F27 ); + defKeySym("F28", Qt::Key_F28 ); + defKeySym("F29", Qt::Key_F29 ); + defKeySym("F30", Qt::Key_F30 ); + defKeySym("F31", Qt::Key_F31 ); + defKeySym("F32", Qt::Key_F32 ); + defKeySym("F33", Qt::Key_F33 ); + defKeySym("F34", Qt::Key_F34 ); + defKeySym("F35", Qt::Key_F35 ); + defKeySym("Super_L", Qt::Key_Super_L ); + defKeySym("Super_R", Qt::Key_Super_R ); + defKeySym("Menu", Qt::Key_Menu ); + defKeySym("Hyper_L", Qt::Key_Hyper_L ); + defKeySym("Hyper_R", Qt::Key_Hyper_R ); + + // Regular keys + defKeySym("Space", Qt::Key_Space ); + defKeySym("Exclam", Qt::Key_Exclam ); + defKeySym("QuoteDbl", Qt::Key_QuoteDbl ); + defKeySym("NumberSign", Qt::Key_NumberSign ); + defKeySym("Dollar", Qt::Key_Dollar ); + defKeySym("Percent", Qt::Key_Percent ); + defKeySym("Ampersand", Qt::Key_Ampersand ); + defKeySym("Apostrophe", Qt::Key_Apostrophe ); + defKeySym("ParenLeft", Qt::Key_ParenLeft ); + defKeySym("ParenRight", Qt::Key_ParenRight ); + defKeySym("Asterisk", Qt::Key_Asterisk ); + defKeySym("Plus", Qt::Key_Plus ); + defKeySym("Comma", Qt::Key_Comma ); + defKeySym("Minus", Qt::Key_Minus ); + defKeySym("Period", Qt::Key_Period ); + defKeySym("Slash", Qt::Key_Slash ); + defKeySym("0", Qt::Key_0 ); + defKeySym("1", Qt::Key_1 ); + defKeySym("2", Qt::Key_2 ); + defKeySym("3", Qt::Key_3 ); + defKeySym("4", Qt::Key_4 ); + defKeySym("5", Qt::Key_5 ); + defKeySym("6", Qt::Key_6 ); + defKeySym("7", Qt::Key_7 ); + defKeySym("8", Qt::Key_8 ); + defKeySym("9", Qt::Key_9 ); + defKeySym("Colon", Qt::Key_Colon ); + defKeySym("Semicolon", Qt::Key_Semicolon ); + defKeySym("Less", Qt::Key_Less ); + defKeySym("Equal", Qt::Key_Equal ); + defKeySym("Greater", Qt::Key_Greater ); + defKeySym("Question", Qt::Key_Question ); + defKeySym("At", Qt::Key_At ); + defKeySym("A", Qt::Key_A ); + defKeySym("B", Qt::Key_B ); + defKeySym("C", Qt::Key_C ); + defKeySym("D", Qt::Key_D ); + defKeySym("E", Qt::Key_E ); + defKeySym("F", Qt::Key_F ); + defKeySym("G", Qt::Key_G ); + defKeySym("H", Qt::Key_H ); + defKeySym("I", Qt::Key_I ); + defKeySym("J", Qt::Key_J ); + defKeySym("K", Qt::Key_K ); + defKeySym("L", Qt::Key_L ); + defKeySym("M", Qt::Key_M ); + defKeySym("N", Qt::Key_N ); + defKeySym("O", Qt::Key_O ); + defKeySym("P", Qt::Key_P ); + defKeySym("Q", Qt::Key_Q ); + defKeySym("R", Qt::Key_R ); + defKeySym("S", Qt::Key_S ); + defKeySym("T", Qt::Key_T ); + defKeySym("U", Qt::Key_U ); + defKeySym("V", Qt::Key_V ); + defKeySym("W", Qt::Key_W ); + defKeySym("X", Qt::Key_X ); + defKeySym("Y", Qt::Key_Y ); + defKeySym("Z", Qt::Key_Z ); + defKeySym("BracketLeft", Qt::Key_BracketLeft ); + defKeySym("Backslash", Qt::Key_Backslash ); + defKeySym("BracketRight", Qt::Key_BracketRight); + defKeySym("AsciiCircum", Qt::Key_AsciiCircum ); + defKeySym("Underscore", Qt::Key_Underscore ); + defKeySym("QuoteLeft", Qt::Key_QuoteLeft ); + defKeySym("BraceLeft", Qt::Key_BraceLeft ); + defKeySym("Bar", Qt::Key_Bar ); + defKeySym("BraceRight", Qt::Key_BraceRight ); + defKeySym("AsciiTilde", Qt::Key_AsciiTilde ); +} + +KeyTransSymbols::KeyTransSymbols() +{ + defModSyms(); + defOprSyms(); + defKeySyms(); +} + +// Global material ----------------------------------------------------------- + +static int keytab_serial = 0; //FIXME: remove,localize + +static QIntDict<KeyTrans> * numb2keymap = 0L; +static QDict<KeyTrans> * path2keymap = 0L; + +KeyTrans* KeyTrans::find(int numb) +{ + KeyTrans* res = numb2keymap->find(numb); + return res ? res : numb2keymap->find(0); +} + +KeyTrans* KeyTrans::find(const char* path) +{ + KeyTrans* res = path2keymap->find(path); + return res ? res : numb2keymap->find(0); +} + +int KeyTrans::count() +{ + return numb2keymap->count(); +} + +void KeyTrans::addKeyTrans() +{ + this->numb = keytab_serial ++; + numb2keymap->insert(numb,this); + path2keymap->insert(path,this); +} + +void KeyTrans::loadAll() +{ + if (!numb2keymap) + numb2keymap = new QIntDict<KeyTrans>; + if (!path2keymap) + path2keymap = new QDict<KeyTrans>; + if (!syms) + syms = new KeyTransSymbols; + + defaultKeyTrans()->addKeyTrans(); + + + QString path = QPEApplication::qpeDir() + "etc/keytabs"; + QDir dir(path); + QStringList lst = dir.entryList("*.keytab"); + + for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) { + QFile file(path + "/" + *it); + KeyTrans* sc = KeyTrans::fromDevice(*it, file); + if (sc) { + sc->addKeyTrans(); + } + } + +} + +// Debugging material ----------------------------------------------------------- +/* +void TestTokenizer(QBuffer &buf) +{ + // opening sequence + + buf.open(IO_ReadOnly); + cc = buf.getch(); + lineno = 1; + + // Test tokenizer + + while (getSymbol(buf)) ReportToken(); + + buf.close(); +} + +void test() +{ + // Opening sequence + + QCString txt = +#include "default.keytab.h" + ; + QBuffer buf(txt); + if (0) TestTokenizer(buf); + if (1) { KeyTrans kt; kt.scanTable(buf); } +} +*/ diff --git a/noncore/apps/opie-console/keytrans.h b/noncore/apps/opie-console/keytrans.h new file mode 100644 index 0000000..ef6ed15 --- a/dev/null +++ b/noncore/apps/opie-console/keytrans.h @@ -0,0 +1,93 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [keytrans.h] X Terminal Emulation */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef KEYTRANS_H +#define KEYTRANS_H + +#include <qstring.h> +#include <qlist.h> +#include <qiodevice.h> + +#define BITS_NewLine 0 +#define BITS_BsHack 1 +#define BITS_Ansi 2 +#define BITS_AppCuKeys 3 +#define BITS_Control 4 +#define BITS_Shift 5 +#define BITS_Alt 6 +#define BITS_COUNT 7 + +#define CMD_send 0 +#define CMD_emitSelection 1 +#define CMD_scrollPageUp 2 +#define CMD_scrollPageDown 3 +#define CMD_scrollLineUp 4 +#define CMD_scrollLineDown 5 +#define CMD_prevSession 6 +#define CMD_nextSession 7 + +#define BITS(x,v) ((((v)!=0)<<(x))) + + +class KeyTrans +{ +public: + KeyTrans(); + ~KeyTrans(); + static KeyTrans* defaultKeyTrans(); + static KeyTrans* fromFile(const char* path); + static KeyTrans* find(int numb); + static KeyTrans* find(const char* path); +public: + static int count(); + static void loadAll(); +public: + bool findEntry(int key, int bits, int* cmd, const char** txt, int* len); +private: + void addKeyTrans(); + static KeyTrans* fromDevice(QString path, QIODevice &buf); +public: + class KeyEntry + { + public: + KeyEntry(int ref, int key, int bits, int mask, int cmd, QString txt); + ~KeyEntry(); + public: + bool matches(int key, int bits, int mask); + QString text(); + public: + int ref; + private: + int key; + int bits; + int mask; + public: + int cmd; + QString txt; + }; +public: + KeyEntry* addEntry(int ref, int key, int bits, int mask, int cmd, QString txt); +private: + QList<KeyEntry> table; +public: //FIXME: we'd do better + QString hdr; + int numb; + QString path; +}; + +#endif diff --git a/noncore/apps/opie-console/keytrans.o b/noncore/apps/opie-console/keytrans.o Binary files differnew file mode 100644 index 0000000..2557f8a --- a/dev/null +++ b/noncore/apps/opie-console/keytrans.o diff --git a/noncore/apps/opie-console/screen.cpp b/noncore/apps/opie-console/screen.cpp new file mode 100644 index 0000000..8ebc47d --- a/dev/null +++ b/noncore/apps/opie-console/screen.cpp @@ -0,0 +1,1197 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [screen.C] Screen Data Type */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \file +*/ + +/*! \class Screen + + \brief The image manipulated by the emulation. + + This class implements the operations of the terminal emulation framework. + It is a complete passive device, driven by the emulation decoder + (TEmuVT102). By this it forms in fact an ADT, that defines operations + on a rectangular image. + + It does neither know how to display its image nor about escape sequences. + It is further independent of the underlying toolkit. By this, one can even + use this module for an ordinary text surface. + + Since the operations are called by a specific emulation decoder, one may + collect their different operations here. + + The state manipulated by the operations is mainly kept in `image', though + it is a little more complex bejond this. See the header file of the class. + + \sa TEWidget \sa VT102Emulation +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +// #include <kdebug.h> + +#include <assert.h> +#include <string.h> +#include <ctype.h> + +#include "screen.h" + +#define HERE printf("%s(%d): here\n",__FILE__,__LINE__) + +//FIXME: this is emulation specific. Use FALSE for xterm, TRUE for ANSI. +//FIXME: see if we can get this from terminfo. +#define BS_CLEARS FALSE + +#define loc(X,Y) ((Y)*columns+(X)) + +/*! creates a `Screen' of `lines' lines and `columns' columns. +*/ + +Screen::Screen(int lines, int columns) +{ + this->lines = lines; + this->columns = columns; + + image = (Character*) malloc(lines*columns*sizeof(Character)); + tabstops = NULL; initTabStops(); + + histCursor = 0; + + clearSelection(); + reset(); +} + +/*! Destructor +*/ + +Screen::~Screen() +{ + free(image); + if (tabstops) free(tabstops); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Normalized Screen Operations */ +/* */ +/* ------------------------------------------------------------------------- */ + +// Cursor Setting -------------------------------------------------------------- + +/*! \section Cursor + + The `cursor' is a location within the screen that is implicitely used in + many operations. The operations within this section allow to manipulate + the cursor explicitly and to obtain it's value. + + The position of the cursor is guarantied to be between (including) 0 and + `columns-1' and `lines-1'. +*/ + +/*! + Move the cursor up. + + The cursor will not be moved beyond the top margin. +*/ + +void Screen::cursorUp(int n) +//=CUU +{ + if (n == 0) n = 1; // Default + int stop = cuY < tmargin ? 0 : tmargin; + cuX = QMIN(columns-1,cuX); // nowrap! + cuY = QMAX(stop,cuY-n); +} + +/*! + Move the cursor down. + + The cursor will not be moved beyond the bottom margin. +*/ + +void Screen::cursorDown(int n) +//=CUD +{ + if (n == 0) n = 1; // Default + int stop = cuY > bmargin ? lines-1 : bmargin; + cuX = QMIN(columns-1,cuX); // nowrap! + cuY = QMIN(stop,cuY+n); +} + +/*! + Move the cursor left. + + The cursor will not move beyond the first column. +*/ + +void Screen::cursorLeft(int n) +//=CUB +{ + if (n == 0) n = 1; // Default + cuX = QMIN(columns-1,cuX); // nowrap! + cuX = QMAX(0,cuX-n); +} + +/*! + Move the cursor left. + + The cursor will not move beyond the rightmost column. +*/ + +void Screen::cursorRight(int n) +//=CUF +{ + if (n == 0) n = 1; // Default + cuX = QMIN(columns-1,cuX+n); +} + +/*! + Set top and bottom margin. +*/ + +void Screen::setMargins(int top, int bot) +//=STBM +{ + if (top == 0) top = 1; // Default + if (bot == 0) bot = lines; // Default + top = top - 1; // Adjust to internal lineno + bot = bot - 1; // Adjust to internal lineno + if ( !( 0 <= top && top < bot && bot < lines ) ) + { fprintf(stderr,"%s(%d) : setRegion(%d,%d) : bad range.\n", + __FILE__,__LINE__,top,bot); + return; // Default error action: ignore + } + tmargin = top; + bmargin = bot; + cuX = 0; + cuY = getMode(MODE_Origin) ? top : 0; +} + +/*! + Move the cursor down one line. + + If cursor is on bottom margin, the region between the + actual top and bottom margin is scrolled up instead. +*/ + +void Screen::index() +//=IND +{ + if (cuY == bmargin) + { + if (tmargin == 0 && bmargin == lines-1) addHistLine(); // hist.history + scrollUp(tmargin,1); + } + else if (cuY < lines-1) + cuY += 1; +} + +/*! + Move the cursor up one line. + + If cursor is on the top margin, the region between the + actual top and bottom margin is scrolled down instead. +*/ + +void Screen::reverseIndex() +//=RI +{ + if (cuY == tmargin) + scrollDown(tmargin,1); + else if (cuY > 0) + cuY -= 1; +} + +/*! + Move the cursor to the begin of the next line. + + If cursor is on bottom margin, the region between the + actual top and bottom margin is scrolled up. +*/ + +void Screen::NextLine() +//=NEL +{ + Return(); index(); +} + +// Line Editing ---------------------------------------------------------------- + +/*! \section inserting / deleting characters +*/ + +/*! erase `n' characters starting from (including) the cursor position. + + The line is filled in from the right with spaces. +*/ + +void Screen::eraseChars(int n) +{ + if (n == 0) n = 1; // Default + int p = QMAX(0,QMIN(cuX+n-1,columns-1)); + clearImage(loc(cuX,cuY),loc(p,cuY),' '); +} + +/*! delete `n' characters starting from (including) the cursor position. + + The line is filled in from the right with spaces. +*/ + +void Screen::deleteChars(int n) +{ + if (n == 0) n = 1; // Default + int p = QMAX(0,QMIN(cuX+n,columns-1)); + moveImage(loc(cuX,cuY),loc(p,cuY),loc(columns-1,cuY)); + clearImage(loc(columns-n,cuY),loc(columns-1,cuY),' '); +} + +/*! insert `n' spaces at the cursor position. + + The cursor is not moved by the operation. +*/ + +void Screen::insertChars(int n) +{ + if (n == 0) n = 1; // Default + int p = QMAX(0,QMIN(columns-1-n,columns-1)); + int q = QMAX(0,QMIN(cuX+n,columns-1)); + moveImage(loc(q,cuY),loc(cuX,cuY),loc(p,cuY)); + clearImage(loc(cuX,cuY),loc(q-1,cuY),' '); +} + +/*! delete `n' lines starting from (including) the cursor position. + + The cursor is not moved by the operation. +*/ + +void Screen::deleteLines(int n) +{ + if (n == 0) n = 1; // Default + scrollUp(cuY,n); +} + +/*! insert `n' lines at the cursor position. + + The cursor is not moved by the operation. +*/ + +void Screen::insertLines(int n) +{ + if (n == 0) n = 1; // Default + scrollDown(cuY,n); +} + +// Mode Operations ----------------------------------------------------------- + +/*! Set a specific mode. */ + +void Screen::setMode(int m) +{ + currParm.mode[m] = TRUE; + switch(m) + { + case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home + } +} + +/*! Reset a specific mode. */ + +void Screen::resetMode(int m) +{ + currParm.mode[m] = FALSE; + switch(m) + { + case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home + } +} + +/*! Save a specific mode. */ + +void Screen::saveMode(int m) +{ + saveParm.mode[m] = currParm.mode[m]; +} + +/*! Restore a specific mode. */ + +void Screen::restoreMode(int m) +{ + currParm.mode[m] = saveParm.mode[m]; +} + +//NOTE: this is a helper function +/*! Return the setting a specific mode. */ +BOOL Screen::getMode(int m) +{ + return currParm.mode[m]; +} + +/*! Save the cursor position and the rendition attribute settings. */ + +void Screen::saveCursor() +{ + sa_cuX = cuX; + sa_cuY = cuY; + sa_cu_re = cu_re; + sa_cu_fg = cu_fg; + sa_cu_bg = cu_bg; +} + +/*! Restore the cursor position and the rendition attribute settings. */ + +void Screen::restoreCursor() +{ + cuX = QMIN(sa_cuX,columns-1); + cuY = QMIN(sa_cuY,lines-1); + cu_re = sa_cu_re; + cu_fg = sa_cu_fg; + cu_bg = sa_cu_bg; + effectiveRendition(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Screen Operations */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! Assing a new size to the screen. + + The topmost left position is maintained, while lower lines + or right hand side columns might be removed or filled with + spaces to fit the new size. + + The region setting is reset to the whole screen and the + tab positions reinitialized. +*/ + +void Screen::resizeImage(int new_lines, int new_columns) +{ + + if (cuY > new_lines-1) + { // attempt to preserve focus and lines + bmargin = lines-1; //FIXME: margin lost + for (int i = 0; i < cuY-(new_lines-1); i++) + { + addHistLine(); scrollUp(0,1); + } + } + + // make new image + Character* newimg = (Character*) malloc(new_lines*new_columns*sizeof(Character)); + + clearSelection(); + + // clear new image + for (int y = 0; y < new_lines; y++) + for (int x = 0; x < new_columns; x++) + { + newimg[y*new_columns+x].c = ' '; + newimg[y*new_columns+x].f = DEFAULT_FORE_COLOR; + newimg[y*new_columns+x].b = DEFAULT_BACK_COLOR; + newimg[y*new_columns+x].r = DEFAULT_RENDITION; + } + int cpy_lines = QMIN(new_lines, lines); + int cpy_columns = QMIN(new_columns,columns); + // copy to new image + for (int y = 0; y < cpy_lines; y++) + for (int x = 0; x < cpy_columns; x++) + { + newimg[y*new_columns+x].c = image[loc(x,y)].c; + newimg[y*new_columns+x].f = image[loc(x,y)].f; + newimg[y*new_columns+x].b = image[loc(x,y)].b; + newimg[y*new_columns+x].r = image[loc(x,y)].r; + } + free(image); + image = newimg; + lines = new_lines; + columns = new_columns; + cuX = QMIN(cuX,columns-1); + cuY = QMIN(cuY,lines-1); + + // FIXME: try to keep values, evtl. + tmargin=0; + bmargin=lines-1; + initTabStops(); + clearSelection(); +} + +/* + Clarifying rendition here and in TEWidget. + + currently, TEWidget's color table is + 0 1 2 .. 9 10 .. 17 + dft_fg, dft_bg, dim 0..7, intensive 0..7 + + cu_fg, cu_bg contain values 0..8; + - 0 = default color + - 1..8 = ansi specified color + + re_fg, re_bg contain values 0..17 + due to the TEWidget's color table + + rendition attributes are + + attr widget screen + -------------- ------ ------ + RE_UNDERLINE XX XX affects foreground only + RE_BLINK XX XX affects foreground only + RE_BOLD XX XX affects foreground only + RE_REVERSE -- XX + RE_TRANSPARENT XX -- affects background only + RE_INTENSIVE XX -- affects foreground only + + Note that RE_BOLD is used in both widget + and screen rendition. Since xterm/vt102 + is to poor to distinguish between bold + (which is a font attribute) and intensive + (which is a color attribute), we translate + this and RE_BOLD in falls eventually appart + into RE_BOLD and RE_INTENSIVE. +*/ + +void Screen::reverseRendition(Character* p) +{ UINT8 f = p->f; UINT8 b = p->b; + p->f = b; p->b = f; //p->r &= ~RE_TRANSPARENT; +} + +void Screen::effectiveRendition() +// calculate rendition +{ + ef_re = cu_re & (RE_UNDERLINE | RE_BLINK); + if (cu_re & RE_REVERSE) + { + ef_fg = cu_bg; + ef_bg = cu_fg; + } + else + { + ef_fg = cu_fg; + ef_bg = cu_bg; + } + if (cu_re & RE_BOLD) + { + if (ef_fg < BASE_COLORS) + ef_fg += BASE_COLORS; + else + ef_fg -= BASE_COLORS; + } +} + +/*! + returns the image. + + Get the size of the image by \sa getLines and \sa getColumns. + + NOTE that the image returned by this function must later be + freed. + +*/ + +Character* Screen::getCookedImage() +{ int x,y; + Character* merged = (Character*) malloc(lines*columns*sizeof(Character)); + Character dft(' ',DEFAULT_FORE_COLOR,DEFAULT_BACK_COLOR,DEFAULT_RENDITION); + + for (y = 0; (y < lines) && (y < (hist.getLines()-histCursor)); y++) + { + int len = QMIN(columns,hist.getLineLen(y+histCursor)); + int yp = y*columns; + int yq = (y+histCursor)*columns; + + hist.getCells(y+histCursor,0,len,merged+yp); + for (x = len; x < columns; x++) merged[yp+x] = dft; + for (x = 0; x < columns; x++) + { int p=x + yp; int q=x + yq; + if ( ( q >= sel_TL ) && ( q <= sel_BR ) ) + reverseRendition(&merged[p]); // for selection + } + } + if (lines >= hist.getLines()-histCursor) + { + for (y = (hist.getLines()-histCursor); y < lines ; y++) + { + int yp = y*columns; + int yq = (y+histCursor)*columns; + int yr = (y-hist.getLines()+histCursor)*columns; + for (x = 0; x < columns; x++) + { int p = x + yp; int q = x + yq; int r = x + yr; + merged[p] = image[r]; + if ( q >= sel_TL && q <= sel_BR ) + reverseRendition(&merged[p]); // for selection + } + + } + } + // evtl. inverse display + if (getMode(MODE_Screen)) + { int i,n = lines*columns; + for (i = 0; i < n; i++) + reverseRendition(&merged[i]); // for reverse display + } + if (getMode(MODE_Cursor) && (cuY+(hist.getLines()-histCursor) < lines)) // cursor visible + reverseRendition(&merged[loc(cuX,cuY+(hist.getLines()-histCursor))]); + return merged; +} + + +/*! +*/ + +void Screen::reset() +{ + setMode(MODE_Wrap ); saveMode(MODE_Wrap ); // wrap at end of margin + resetMode(MODE_Origin); saveMode(MODE_Origin); // position refere to [1,1] + resetMode(MODE_Insert); saveMode(MODE_Insert); // overstroke + setMode(MODE_Cursor); // cursor visible + resetMode(MODE_Screen); // screen not inverse + resetMode(MODE_NewLine); + + tmargin=0; + bmargin=lines-1; + + setDefaultRendition(); + saveCursor(); + + clear(); +} + +/*! Clear the entire screen and home the cursor. +*/ + +void Screen::clear() +{ + clearEntireScreen(); + home(); +} + +/*! Moves the cursor left one column. +*/ + +void Screen::BackSpace() +{ + cuX = QMAX(0,cuX-1); + if (BS_CLEARS) image[loc(cuX,cuY)].c = ' '; +} + +/*! +*/ + +void Screen::Tabulate() +{ + // note that TAB is a format effector (does not write ' '); + cursorRight(1); while(cuX < columns-1 && !tabstops[cuX]) cursorRight(1); +} + +void Screen::clearTabStops() +{ + for (int i = 0; i < columns; i++) tabstops[i-1] = FALSE; +} + +void Screen::changeTabStop(bool set) +{ + if (cuX >= columns) return; + tabstops[cuX] = set; +} + +void Screen::initTabStops() +{ + if (tabstops) free(tabstops); + tabstops = (bool*)malloc(columns*sizeof(bool)); + // Arrg! The 1st tabstop has to be one longer than the other. + // i.e. the kids start counting from 0 instead of 1. + // Other programs might behave correctly. Be aware. + for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0); +} + +/*! + This behaves either as IND (Screen::Index) or as NEL (Screen::NextLine) + depending on the NewLine Mode (LNM). This mode also + affects the key sequence returned for newline ([CR]LF). +*/ + +void Screen::NewLine() +{ + if (getMode(MODE_NewLine)) Return(); + index(); +} + +/*! put `c' literally onto the screen at the current cursor position. + + VT100 uses the convention to produce an automatic newline (am) + with the *first* character that would fall onto the next line (xenl). +*/ + +void Screen::checkSelection(int from, int to) +{ + if (sel_begin == -1) return; + int scr_TL = loc(0, hist.getLines()); + //Clear entire selection if it overlaps region [from, to] + if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) ) + { + clearSelection(); + } +} + +void Screen::ShowCharacter(unsigned short c) +{ + // Note that VT100 does wrapping BEFORE putting the character. + // This has impact on the assumption of valid cursor positions. + // We indicate the fact that a newline has to be triggered by + // putting the cursor one right to the last column of the screen. + + if (cuX >= columns) + { + if (getMode(MODE_Wrap)) NextLine(); else cuX = columns-1; + } + + if (getMode(MODE_Insert)) insertChars(1); + + int i = loc(cuX,cuY); + + checkSelection(i, i); // check if selection is still valid. + + image[i].c = c; + image[i].f = ef_fg; + image[i].b = ef_bg; + image[i].r = ef_re; + + cuX += 1; +} + +// Region commands ------------------------------------------------------------- + + +/*! scroll up `n' lines within current region. + The `n' new lines are cleared. + \sa setRegion \sa scrollDown +*/ + +void Screen::scrollUp(int from, int n) +{ + if (n <= 0 || from + n > bmargin) return; + //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. + moveImage(loc(0,from),loc(0,from+n),loc(columns-1,bmargin)); + clearImage(loc(0,bmargin-n+1),loc(columns-1,bmargin),' '); +} + +/*! scroll down `n' lines within current region. + The `n' new lines are cleared. + \sa setRegion \sa scrollUp +*/ + +void Screen::scrollDown(int from, int n) +{ +//FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. + if (n <= 0) return; + if (from > bmargin) return; + if (from + n > bmargin) n = bmargin - from; + moveImage(loc(0,from+n),loc(0,from),loc(columns-1,bmargin-n)); + clearImage(loc(0,from),loc(columns-1,from+n-1),' '); +} + +/*! position the cursor to a specific line and column. */ +void Screen::setCursorYX(int y, int x) +{ + setCursorY(y); setCursorX(x); +} + +/*! Set the cursor to x-th line. */ + +void Screen::setCursorX(int x) +{ + if (x == 0) x = 1; // Default + x -= 1; // Adjust + cuX = QMAX(0,QMIN(columns-1, x)); +} + +/*! Set the cursor to y-th line. */ + +void Screen::setCursorY(int y) +{ + if (y == 0) y = 1; // Default + y -= 1; // Adjust + cuY = QMAX(0,QMIN(lines -1, y + (getMode(MODE_Origin) ? tmargin : 0) )); +} + +/*! set cursor to the `left upper' corner of the screen (1,1). +*/ + +void Screen::home() +{ + cuX = 0; + cuY = 0; +} + +/*! set cursor to the begin of the current line. +*/ + +void Screen::Return() +{ + cuX = 0; +} + +/*! returns the current cursor columns. +*/ + +int Screen::getCursorX() +{ + return cuX; +} + +/*! returns the current cursor line. +*/ + +int Screen::getCursorY() +{ + return cuY; +} + +// Erasing --------------------------------------------------------------------- + +/*! \section Erasing + + This group of operations erase parts of the screen contents by filling + it with spaces colored due to the current rendition settings. + + Althought the cursor position is involved in most of these operations, + it is never modified by them. +*/ + +/*! fill screen between (including) `loca' and `loce' with spaces. + + This is an internal helper functions. The parameter types are internal + addresses of within the screen image and make use of the way how the + screen matrix is mapped to the image vector. +*/ + +void Screen::clearImage(int loca, int loce, char c) +{ int i; + int scr_TL=loc(0,hist.getLines()); + //FIXME: check positions + + //Clear entire selection if it overlaps region to be moved... + if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) ) + { + clearSelection(); + } + for (i = loca; i <= loce; i++) + { + image[i].c = c; + image[i].f = ef_fg; //DEFAULT_FORE_COLOR; //FIXME: xterm and linux/ansi + image[i].b = ef_bg; //DEFAULT_BACK_COLOR; // many have different + image[i].r = ef_re; //DEFAULT_RENDITION; // ideas here. + } +} + +/*! move image between (including) `loca' and `loce' to 'dst'. + + This is an internal helper functions. The parameter types are internal + addresses of within the screen image and make use of the way how the + screen matrix is mapped to the image vector. +*/ + +void Screen::moveImage(int dst, int loca, int loce) +{ +//FIXME: check positions + if (loce < loca) { + // kdDebug() << "WARNING!!! call to Screen:moveImage with loce < loca!" << endl; + return; + } + memmove(&image[dst],&image[loca],(loce-loca+1)*sizeof(Character)); +} + +/*! clear from (including) current cursor position to end of screen. +*/ + +void Screen::clearToEndOfScreen() +{ + clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' '); +} + +/*! clear from begin of screen to (including) current cursor position. +*/ + +void Screen::clearToBeginOfScreen() +{ + clearImage(loc(0,0),loc(cuX,cuY),' '); +} + +/*! clear the entire screen. +*/ + +void Screen::clearEntireScreen() +{ + clearImage(loc(0,0),loc(columns-1,lines-1),' '); +} + +/*! fill screen with 'E' + This is to aid screen alignment +*/ + +void Screen::helpAlign() +{ + clearImage(loc(0,0),loc(columns-1,lines-1),'E'); +} + +/*! clear from (including) current cursor position to end of current cursor line. +*/ + +void Screen::clearToEndOfLine() +{ + clearImage(loc(cuX,cuY),loc(columns-1,cuY),' '); +} + +/*! clear from begin of current cursor line to (including) current cursor position. +*/ + +void Screen::clearToBeginOfLine() +{ + clearImage(loc(0,cuY),loc(cuX,cuY),' '); +} + +/*! clears entire current cursor line +*/ + +void Screen::clearEntireLine() +{ + clearImage(loc(0,cuY),loc(columns-1,cuY),' '); +} + +// Rendition ------------------------------------------------------------------ + +/*! + set rendition mode +*/ + +void Screen::setRendition(int re) +{ + cu_re |= re; + effectiveRendition(); +} + +/*! + reset rendition mode +*/ + +void Screen::resetRendition(int re) +{ + cu_re &= ~re; + effectiveRendition(); +} + +/*! +*/ + +void Screen::setDefaultRendition() +{ + setForeColorToDefault(); + setBackColorToDefault(); + cu_re = DEFAULT_RENDITION; + effectiveRendition(); +} + +/*! +*/ + +void Screen::setForeColor(int fgcolor) +{ + cu_fg = (fgcolor&7)+((fgcolor&8) ? 4+8 : 2); + effectiveRendition(); +} + +/*! +*/ + +void Screen::setBackColor(int bgcolor) +{ + cu_bg = (bgcolor&7)+((bgcolor&8) ? 4+8 : 2); + effectiveRendition(); +} + +/*! +*/ + +void Screen::setBackColorToDefault() +{ + cu_bg = DEFAULT_BACK_COLOR; + effectiveRendition(); +} + +/*! +*/ + +void Screen::setForeColorToDefault() +{ + cu_fg = DEFAULT_FORE_COLOR; + effectiveRendition(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Marking & Selection */ +/* */ +/* ------------------------------------------------------------------------- */ + +void Screen::clearSelection() +{ + sel_BR = -1; + sel_TL = -1; + sel_begin = -1; +} + +void Screen::setSelBeginXY(const int x, const int y) +{ + sel_begin = loc(x,y+histCursor) ; + sel_BR = sel_begin; + sel_TL = sel_begin; +} + +void Screen::setSelExtentXY(const int x, const int y) +{ + if (sel_begin == -1) return; + int l = loc(x,y + histCursor); + + if (l < sel_begin) + { + sel_TL = l; + sel_BR = sel_begin; + } + else + { + /* FIXME, HACK to correct for x too far to the right... */ + if (( x == columns )|| (x == 0)) l--; + + sel_TL = sel_begin; + sel_BR = l; + } +} + +QString Screen::getSelText(const BOOL preserve_line_breaks) +{ + if (sel_begin == -1) + return QString::null; // Selection got clear while selecting. + + int *m; // buffer to fill. + int s, d; // source index, dest. index. + int hist_BR = loc(0, hist.getLines()); + int hY = sel_TL / columns; + int hX = sel_TL % columns; + int eol; // end of line + + s = sel_TL; // tracks copy in source. + + // allocate buffer for maximum + // possible size... + d = (sel_BR - sel_TL) / columns + 1; + m = new int[d * (columns + 1) + 2]; + d = 0; + + while (s <= sel_BR) + { + if (s < hist_BR) + { // get lines from hist.history + // buffer. + eol = hist.getLineLen(hY); + + if ((hY == (sel_BR / columns)) && + (eol >= (sel_BR % columns))) + { + eol = sel_BR % columns + 1; + } + + while (hX < eol) + { + m[d++] = hist.getCell(hY, hX++).c; + s++; + } + + if (s <= sel_BR) + { + // The line break handling + // It's different from the screen + // image case! + if (eol % columns == 0) + { + // That's either a completely filled + // line or an empty line + if (eol == 0) + { + m[d++] = '\n'; + } + else + { + // We have a full line. + // FIXME: How can we handle newlines + // at this position?! + } + } + else if ((eol + 1) % columns == 0) + { + // FIXME: We don't know if this was a + // space at the last position or a + // short line!! + m[d++] = ' '; + } + else + { + // We have a short line here. Put a + // newline or a space into the + // buffer. + m[d++] = preserve_line_breaks ? '\n' : ' '; + } + } + + hY++; + hX = 0; + s = hY * columns; + } + else + { // or from screen image. + eol = (s / columns + 1) * columns - 1; + + if (eol < sel_BR) + { + while ((eol > s) && + isspace(image[eol - hist_BR].c)) + { + eol--; + } + } + else + { + eol = sel_BR; + } + + while (s <= eol) + { + m[d++] = image[s++ - hist_BR].c; + } + + if (eol < sel_BR) + { + // eol processing see below ... + if ((eol + 1) % columns == 0) + { + if (image[eol - hist_BR].c == ' ') + { + m[d++] = ' '; + } + } + else + { + m[d++] = ((preserve_line_breaks || + ((eol % columns) == 0)) ? + '\n' : ' '); + } + } + + s = (eol / columns + 1) * columns; + } + } + + QChar* qc = new QChar[d]; + + for (int i = 0; i < d; i++) + { + qc[i] = m[i]; + } + + QString res(qc, d); + + delete m; + delete qc; + + return res; +} +/* above ... end of line processing for selection -- psilva +cases: + +1) (eol+1)%columns == 0 --> the whole line is filled. + If the last char is a space, insert (preserve) space. otherwise + leave the text alone, so that words that are broken by linewrap + are preserved. + +FIXME: + * this suppresses \n for command output that is + sized to the exact column width of the screen. + +2) eol%columns == 0 --> blank line. + insert a \n unconditionally. + Do it either you would because you are in preserve_line_break mode, + or because it's an ASCII paragraph delimiter, so even when + not preserving line_breaks, you want to preserve paragraph breaks. + +3) else --> partially filled line + insert a \n in preserve line break mode, else a space + The space prevents concatenation of the last word of one + line with the first of the next. + +*/ + +void Screen::addHistLine() +{ + assert(hasScroll() || histCursor == 0); + + // add to hist buffer + // we have to take care about scrolling, too... + + if (hasScroll()) + { Character dft; + + int end = columns-1; + while (end >= 0 && image[end] == dft) + end -= 1; + + hist.addCells(image,end+1); + hist.addLine(); + + // adjust history cursor + histCursor += (hist.getLines()-1 == histCursor); + } + + if (!hasScroll()) histCursor = 0; //FIXME: a poor workaround +} + +void Screen::setHistCursor(int cursor) +{ + histCursor = cursor; //FIXME:rangecheck +} + +int Screen::getHistCursor() +{ + return histCursor; +} + +int Screen::getHistLines() +{ + return hist.getLines(); +} + +void Screen::setScroll(bool on) +{ + histCursor = 0; + clearSelection(); + hist.setScroll(on); +} + +bool Screen::hasScroll() +{ + return hist.hasScroll(); +} diff --git a/noncore/apps/opie-console/screen.h b/noncore/apps/opie-console/screen.h new file mode 100644 index 0000000..cd7422a --- a/dev/null +++ b/noncore/apps/opie-console/screen.h @@ -0,0 +1,259 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [screen.h] Screen Data Type */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef SCREEN_H +#define SCREEN_H + +/*! \file +*/ + +#include "common.h" +#include "history.h" + +#define MODE_Origin 0 +#define MODE_Wrap 1 +#define MODE_Insert 2 +#define MODE_Screen 3 +#define MODE_Cursor 4 +#define MODE_NewLine 5 +#define MODES_SCREEN 6 + +/*! +*/ +struct ScreenParm +{ + int mode[MODES_SCREEN]; +}; + + +class Screen +{ +public: + Screen(int lines, int columns); + ~Screen(); + +public: // these are all `Screen' operations + // + // VT100/2 Operations ------------------ + // + // Cursor Movement + // + void cursorUp (int n); + void cursorDown (int n); + void cursorLeft (int n); + void cursorRight (int n); + void setCursorY (int y); + void setCursorX (int x); + void setCursorYX (int y, int x); + void setMargins (int t, int b); + // + // Cursor Movement with Scrolling + // + void NewLine (); + void NextLine (); + void index (); + void reverseIndex(); + // + void Return (); + void BackSpace (); + void Tabulate (); + // + // Editing + // + void eraseChars (int n); + void deleteChars (int n); + void insertChars (int n); + void deleteLines (int n); + void insertLines (int n); + // + // ------------------------------------- + // + void clearTabStops(); + void changeTabStop(bool set); + // + void resetMode (int n); + void setMode (int n); + void saveMode (int n); + void restoreMode (int n); + // + void saveCursor (); + void restoreCursor(); + // + // ------------------------------------- + // + void clearEntireScreen(); + void clearToEndOfScreen(); + void clearToBeginOfScreen(); + // + void clearEntireLine(); + void clearToEndOfLine(); + void clearToBeginOfLine(); + // + void helpAlign (); + // + // ------------------------------------- + // + void setRendition (int rendition); + void resetRendition(int rendition); + void setForeColor (int fgcolor); + void setBackColor (int bgcolor); + // + void setDefaultRendition(); + void setForeColorToDefault(); + void setBackColorToDefault(); + // + // ------------------------------------- + // + BOOL getMode (int n); + // + // only for report cursor position + // + int getCursorX(); + int getCursorY(); + // + // ------------------------------------- + // + void clear(); + void home(); + void reset(); + // + void ShowCharacter(unsigned short c); + // + void resizeImage(int new_lines, int new_columns); + // + Character* getCookedImage(); + + /*! return the number of lines. */ + int getLines() { return lines; } + /*! return the number of columns. */ + int getColumns() { return columns; } + + /*! set the position of the history cursor. */ + void setHistCursor(int cursor); + /*! return the position of the history cursor. */ + int getHistCursor(); + + int getHistLines (); + void setScroll(bool on); + bool hasScroll(); + + // + // Selection + // + void setSelBeginXY(const int x, const int y); + void setSelExtentXY(const int x, const int y); + void clearSelection(); + QString getSelText(const BOOL preserve_line_breaks); + + void checkSelection(int from, int to); + +private: // helper + + void clearImage(int loca, int loce, char c); + void moveImage(int dst, int loca, int loce); + + void scrollUp(int from, int i); + void scrollDown(int from, int i); + + void addHistLine(); + + void initTabStops(); + + void effectiveRendition(); + void reverseRendition(Character* p); + +private: + + /* + The state of the screen is more complex as one would + expect first. The screem does really do part of the + emulation providing state informations in form of modes, + margins, tabulators, cursor etc. + + Even more unexpected are variables to save and restore + parts of the state. + */ + + // screen image ---------------- + + int lines; + int columns; + Character *image; // [lines][columns] + + // history buffer --------------- + + int histCursor; // display position relative to start of the history buffer + HistoryScroll hist; + + // cursor location + + int cuX; + int cuY; + + // cursor color and rendition info + + UINT8 cu_fg; // foreground + UINT8 cu_bg; // background + UINT8 cu_re; // rendition + + // margins ---------------- + + int tmargin; // top margin + int bmargin; // bottom margin + + // states ---------------- + + ScreenParm currParm; + + // ---------------------------- + + bool* tabstops; + + // selection ------------------- + + int sel_begin; // The first location selected. + int sel_TL; // TopLeft Location. + int sel_BR; // Bottom Right Location. + + // effective colors and rendition ------------ + + UINT8 ef_fg; // These are derived from + UINT8 ef_bg; // the cu_* variables above + UINT8 ef_re; // to speed up operation + + // + // save cursor, rendition & states ------------ + // + + // cursor location + + int sa_cuX; + int sa_cuY; + + // rendition info + + UINT8 sa_cu_re; + UINT8 sa_cu_fg; + UINT8 sa_cu_bg; + + // modes + + ScreenParm saveParm; +}; + +#endif // TESCREEN_H diff --git a/noncore/apps/opie-console/screen.o b/noncore/apps/opie-console/screen.o Binary files differnew file mode 100644 index 0000000..b2d0420 --- a/dev/null +++ b/noncore/apps/opie-console/screen.o diff --git a/noncore/apps/opie-console/vt102emulation.cpp b/noncore/apps/opie-console/vt102emulation.cpp new file mode 100644 index 0000000..dc977f5 --- a/dev/null +++ b/noncore/apps/opie-console/vt102emulation.cpp @@ -0,0 +1,1029 @@ +/* ------------------------------------------------------------------------- */ +/* */ +/* [vt102emulation.cpp] VT102 Terminal Emulation */ +/* */ +/* ------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* ------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ + +/*! \class Vt102Emulation + + \brief Actual Emulation for Konsole + + \sa Widget \sa Screen \sa EmulationLayer +*/ + +#include "vt102emulation.h" +#include "widget.h" +#include "screen.h" +#include "keytrans.h" + +#include <stdio.h> +#include <unistd.h> +#include <qkeycode.h> +#include <qtextcodec.h> + + +/* VT102 Terminal Emulation + + This class puts together the screens, the pty and the widget to a + complete terminal emulation. Beside combining it's componentes, it + handles the emulations's protocol. + + This module consists of the following sections: + + - Constructor/Destructor + - Incoming Bytes Event pipeline + - Outgoing Bytes + - Mouse Events + - Keyboard Events + - Modes and Charset State + - Diagnostics +*/ + + +/* ------------------------------------------------------------------------- */ +/* */ +/* Constructor / Destructor */ +/* */ +/* ------------------------------------------------------------------------- */ + +/* + Nothing really intesting happens here. +*/ + +/*! +*/ + +Vt102Emulation::Vt102Emulation(Widget* gui) : EmulationLayer(gui) +{ + QObject::connect(gui,SIGNAL(mouseSignal(int,int,int)), + this,SLOT(onMouse(int,int,int))); + initTokenizer(); + reset(); +} + +/*! +*/ + +Vt102Emulation::~Vt102Emulation() +{ +} + +/*! +*/ + +void Vt102Emulation::reset() +{ + resetToken(); + resetModes(); + resetCharset(0); screen[0]->reset(); + resetCharset(1); screen[0]->reset(); + setCodec(0); + setKeytrans("linux.keytab"); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Processing the incoming byte stream */ +/* */ +/* ------------------------------------------------------------------------- */ + +/* Incoming Bytes Event pipeline + + This section deals with decoding the incoming character stream. + Decoding means here, that the stream is first seperated into `tokens' + which are then mapped to a `meaning' provided as operations by the + `TEScreen' class or by the emulation class itself. + + The pipeline proceeds as follows: + + - Tokenizing the ESC codes (onRcvChar) + - VT100 code page translation of plain characters (applyCharset) + - Interpretation of ESC codes (tau) + + The escape codes and their meaning are described in the + technical reference of this program. +*/ + +// Tokens ------------------------------------------------------------------ -- + +/* + Since the tokens are the central notion if this section, we've put them + in front. They provide the syntactical elements used to represent the + terminals operations as byte sequences. + + They are encodes here into a single machine word, so that we can later + switch over them easily. Depending on the token itself, additional + argument variables are filled with parameter values. + + The tokens are defined below: + + - CHR - Printable characters (32..255 but DEL (=127)) + - CTL - Control characters (0..31 but ESC (= 27), DEL) + - ESC - Escape codes of the form <ESC><CHR but `[]()+*#'> + - ESC_DE - Escape codes of the form <ESC><any of `()+*#%'> C + - CSI_PN - Escape codes of the form <ESC>'[' {Pn} ';' {Pn} C + - CSI_PS - Escape codes of the form <ESC>'[' {Pn} ';' ... C + - CSI_PR - Escape codes of the form <ESC>'[' '?' {Pn} ';' ... C + - VT52 - VT52 escape codes + - <ESC><Chr> + - <ESC>'Y'{Pc}{Pc} + - XTE_HA - Xterm hacks <ESC>`]' {Pn} `;' {Text} <BEL> + note that this is handled differently + + The last two forms allow list of arguments. Since the elements of + the lists are treated individually the same way, they are passed + as individual tokens to the interpretation. Further, because the + meaning of the parameters are names (althought represented as numbers), + they are includes within the token ('N'). + +*/ + +#define TY_CONSTR(T,A,N) ( ((((int)N) & 0xffff) << 16) | ((((int)A) & 0xff) << 8) | (((int)T) & 0xff) ) + +#define TY_CHR___( ) TY_CONSTR(0,0,0) +#define TY_CTL___(A ) TY_CONSTR(1,A,0) +#define TY_ESC___(A ) TY_CONSTR(2,A,0) +#define TY_ESC_CS(A,B) TY_CONSTR(3,A,B) +#define TY_ESC_DE(A ) TY_CONSTR(4,A,0) +#define TY_CSI_PS(A,N) TY_CONSTR(5,A,N) +#define TY_CSI_PN(A ) TY_CONSTR(6,A,0) +#define TY_CSI_PR(A,N) TY_CONSTR(7,A,N) + +#define TY_VT52__(A ) TY_CONSTR(8,A,0) + +// Tokenizer --------------------------------------------------------------- -- + +/* The tokenizers state + + The state is represented by the buffer (pbuf, ppos), + and accompanied by decoded arguments kept in (argv,argc). + Note that they are kept internal in the tokenizer. +*/ + +void Vt102Emulation::resetToken() +{ + ppos = 0; argc = 0; argv[0] = 0; argv[1] = 0; +} + +void Vt102Emulation::addDigit(int dig) +{ + argv[argc] = 10*argv[argc] + dig; +} + +void Vt102Emulation::addArgument() +{ + argc = QMIN(argc+1,MAXARGS-1); + argv[argc] = 0; +} + +void Vt102Emulation::pushToToken(int cc) +{ + pbuf[ppos] = cc; + ppos = QMIN(ppos+1,MAXPBUF-1); +} + +// Character Classes used while decoding + +#define CTL 1 +#define CHR 2 +#define CPN 4 +#define DIG 8 +#define SCS 16 +#define GRP 32 + +void Vt102Emulation::initTokenizer() +{ int i; UINT8* s; + for(i = 0; i < 256; i++) tbl[ i] = 0; + for(i = 0; i < 32; i++) tbl[ i] |= CTL; + for(i = 32; i < 256; i++) tbl[ i] |= CHR; + for(s = (UINT8*)"@ABCDGHLMPXcdfry"; *s; s++) tbl[*s] |= CPN; + for(s = (UINT8*)"0123456789" ; *s; s++) tbl[*s] |= DIG; + for(s = (UINT8*)"()+*%" ; *s; s++) tbl[*s] |= SCS; + for(s = (UINT8*)"()+*#[]%" ; *s; s++) tbl[*s] |= GRP; + resetToken(); +} + +/* Ok, here comes the nasty part of the decoder. + + Instead of keeping an explicit state, we deduce it from the + token scanned so far. It is then immediately combined with + the current character to form a scanning decision. + + This is done by the following defines. + + - P is the length of the token scanned so far. + - L (often P-1) is the position on which contents we base a decision. + - C is a character or a group of characters (taken from 'tbl'). + + Note that they need to applied in proper order. +*/ + +#define lec(P,L,C) (p == (P) && s[(L)] == (C)) +#define lun( ) (p == 1 && cc >= 32 ) +#define les(P,L,C) (p == (P) && s[L] < 256 && (tbl[s[(L)]] & (C)) == (C)) +#define eec(C) (p >= 3 && cc == (C)) +#define ees(C) (p >= 3 && cc < 256 && (tbl[ cc ] & (C)) == (C)) +#define eps(C) (p >= 3 && s[2] != '?' && cc < 256 && (tbl[ cc ] & (C)) == (C)) +#define epp( ) (p >= 3 && s[2] == '?' ) +#define egt( ) (p == 3 && s[2] == '>' ) +#define Xpe (ppos>=2 && pbuf[1] == ']' ) +#define Xte (Xpe && cc == 7 ) +#define ces(C) ( cc < 256 && (tbl[ cc ] & (C)) == (C) && !Xte) + +#define ESC 27 +#define CNTL(c) ((c)-'@') + +// process an incoming unicode character + +void Vt102Emulation::onRcvChar(int cc) +{ int i; + + if (cc == 127) return; //VT100: ignore. + + if (ces( CTL)) + { // DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100 + // This means, they do neither a resetToken nor a pushToToken. Some of them, do + // of course. Guess this originates from a weakly layered handling of the X-on + // X-off protocol, which comes really below this level. + if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) resetToken(); //VT100: CAN or SUB + if (cc != ESC) { tau( TY_CTL___(cc+'@' ), 0, 0); return; } + } + + pushToToken(cc); // advance the state + + int* s = pbuf; + int p = ppos; + + if (getMode(MODE_Ansi)) // decide on proper action + { + if (lec(1,0,ESC)) { return; } + if (les(2,1,GRP)) { return; } + if (Xte ) { XtermHack(); resetToken(); return; } + if (Xpe ) { return; } + if (lec(3,2,'?')) { return; } + if (lec(3,2,'>')) { return; } + if (lun( )) { tau( TY_CHR___(), applyCharset(cc), 0); resetToken(); return; } + if (lec(2,0,ESC)) { tau( TY_ESC___(s[1]), 0, 0); resetToken(); return; } + if (les(3,1,SCS)) { tau( TY_ESC_CS(s[1],s[2]), 0, 0); resetToken(); return; } + if (lec(3,1,'#')) { tau( TY_ESC_DE(s[2]), 0, 0); resetToken(); return; } +// if (egt( )) { tau( TY_CSI_PG(cc ), '>', 0); resetToken(); return; } + if (eps( CPN)) { tau( TY_CSI_PN(cc), argv[0],argv[1]); resetToken(); return; } + if (ees( DIG)) { addDigit(cc-'0'); return; } + if (eec( ';')) { addArgument(); return; } + for (i=0;i<=argc;i++) + if (epp( )) tau( TY_CSI_PR(cc,argv[i]), 0, 0); else + tau( TY_CSI_PS(cc,argv[i]), 0, 0); + resetToken(); + } + else // mode VT52 + { + if (lec(1,0,ESC)) return; + if (les(1,0,CHR)) { tau( TY_CHR___( ), s[0], 0); resetToken(); return; } + if (lec(2,1,'Y')) return; + if (lec(3,1,'Y')) return; + if (p < 4) { tau( TY_VT52__(s[1] ), 0, 0); resetToken(); return; } + tau( TY_VT52__(s[1] ), s[2],s[3]); resetToken(); return; + } +} + +void Vt102Emulation::XtermHack() +{ int i,arg = 0; + for (i = 2; i < ppos && '0'<=pbuf[i] && pbuf[i]<'9' ; i++) + arg = 10*arg + (pbuf[i]-'0'); + if (pbuf[i] != ';') { ReportErrorToken(); return; } + QChar *str = new QChar[ppos-i-2]; + for (int j = 0; j < ppos-i-2; j++) str[j] = pbuf[i+1+j]; + QString unistr(str,ppos-i-2); + // arg == 1 doesn't change the title. In XTerm it only changes the icon name + // (btw: arg=0 changes title and icon, arg=1 only icon, arg=2 only title + if (arg == 0 || arg == 2) emit changeTitle(arg,unistr); + delete [] str; +} + +// Interpreting Codes --------------------------------------------------------- + +/* + Now that the incoming character stream is properly tokenized, + meaning is assigned to them. These are either operations of + the current screen, or of the emulation class itself. + + The token to be interpreteted comes in as a machine word + possibly accompanied by two parameters. + + Likewise, the operations assigned to, come with up to two + arguments. One could consider to make up a proper table + from the function below. + + The technical reference manual provides more informations + about this mapping. +*/ + +void Vt102Emulation::tau( int token, int p, int q ) +{ +//scan_buffer_report(); +//if (token == TY_CHR___()) printf("%c",p); else +//printf("tau(%d,%d,%d, %d,%d)\n",(token>>0)&0xff,(token>>8)&0xff,(token>>16)&0xffff,p,q); + switch (token) + { + + case TY_CHR___( ) : scr->ShowCharacter (p ); break; //UTF16 + + // 127 DEL : ignored on input + + case TY_CTL___('@' ) : /* NUL: ignored */ break; + case TY_CTL___('A' ) : /* SOH: ignored */ break; + case TY_CTL___('B' ) : /* STX: ignored */ break; + case TY_CTL___('C' ) : /* ETX: ignored */ break; + case TY_CTL___('D' ) : /* EOT: ignored */ break; + case TY_CTL___('E' ) : reportAnswerBack ( ); break; //VT100 + case TY_CTL___('F' ) : /* ACK: ignored */ break; + case TY_CTL___('G' ) : gui->Bell ( ); break; //VT100 + case TY_CTL___('H' ) : scr->BackSpace ( ); break; //VT100 + case TY_CTL___('I' ) : scr->Tabulate ( ); break; //VT100 + case TY_CTL___('J' ) : scr->NewLine ( ); break; //VT100 + case TY_CTL___('K' ) : scr->NewLine ( ); break; //VT100 + case TY_CTL___('L' ) : scr->NewLine ( ); break; //VT100 + case TY_CTL___('M' ) : scr->Return ( ); break; //VT100 + + case TY_CTL___('N' ) : useCharset ( 1); break; //VT100 + case TY_CTL___('O' ) : useCharset ( 0); break; //VT100 + + case TY_CTL___('P' ) : /* DLE: ignored */ break; + case TY_CTL___('Q' ) : /* DC1: XON continue */ break; //VT100 + case TY_CTL___('R' ) : /* DC2: ignored */ break; + case TY_CTL___('S' ) : /* DC3: XOFF halt */ break; //VT100 + case TY_CTL___('T' ) : /* DC4: ignored */ break; + case TY_CTL___('U' ) : /* NAK: ignored */ break; + case TY_CTL___('V' ) : /* SYN: ignored */ break; + case TY_CTL___('W' ) : /* ETB: ignored */ break; + case TY_CTL___('X' ) : scr->ShowCharacter ( 0x2592); break; //VT100 + case TY_CTL___('Y' ) : /* EM : ignored */ break; + case TY_CTL___('Z' ) : scr->ShowCharacter ( 0x2592); break; //VT100 + case TY_CTL___('[' ) : /* ESC: cannot be seen here. */ break; + case TY_CTL___('\\' ) : /* FS : ignored */ break; + case TY_CTL___(']' ) : /* GS : ignored */ break; + case TY_CTL___('^' ) : /* RS : ignored */ break; + case TY_CTL___('_' ) : /* US : ignored */ break; + + case TY_ESC___('D' ) : scr->index ( ); break; //VT100 + case TY_ESC___('E' ) : scr->NextLine ( ); break; //VT100 + case TY_ESC___('H' ) : scr->changeTabStop (TRUE ); break; //VT100 + case TY_ESC___('M' ) : scr->reverseIndex ( ); break; //VT100 + case TY_ESC___('Z' ) : reportTerminalType ( ); break; + case TY_ESC___('c' ) : reset ( ); break; + + case TY_ESC___('n' ) : useCharset ( 2); break; + case TY_ESC___('o' ) : useCharset ( 3); break; + case TY_ESC___('7' ) : saveCursor ( ); break; + case TY_ESC___('8' ) : restoreCursor ( ); break; + + case TY_ESC___('=' ) : setMode (MODE_AppKeyPad); break; + case TY_ESC___('>' ) : resetMode (MODE_AppKeyPad); break; + case TY_ESC___('<' ) : setMode (MODE_Ansi ); break; //VT100 + + case TY_ESC_CS('(', '0') : setCharset (0, '0'); break; //VT100 + case TY_ESC_CS('(', 'A') : setCharset (0, 'A'); break; //VT100 + case TY_ESC_CS('(', 'B') : setCharset (0, 'B'); break; //VT100 + + case TY_ESC_CS(')', '0') : setCharset (1, '0'); break; //VT100 + case TY_ESC_CS(')', 'A') : setCharset (1, 'A'); break; //VT100 + case TY_ESC_CS(')', 'B') : setCharset (1, 'B'); break; //VT100 + + case TY_ESC_CS('*', '0') : setCharset (2, '0'); break; //VT100 + case TY_ESC_CS('*', 'A') : setCharset (2, 'A'); break; //VT100 + case TY_ESC_CS('*', 'B') : setCharset (2, 'B'); break; //VT100 + + case TY_ESC_CS('+', '0') : setCharset (3, '0'); break; //VT100 + case TY_ESC_CS('+', 'A') : setCharset (3, 'A'); break; //VT100 + case TY_ESC_CS('+', 'B') : setCharset (3, 'B'); break; //VT100 + + case TY_ESC_CS('%', 'G') : setCodec (1 ); break; //LINUX + case TY_ESC_CS('%', '@') : setCodec (0 ); break; //LINUX + + case TY_ESC_DE('3' ) : /* IGNORED: double high, top half */ break; + case TY_ESC_DE('4' ) : /* IGNORED: double high, bottom half */ break; + case TY_ESC_DE('5' ) : /* IGNORED: single width, single high*/ break; + case TY_ESC_DE('6' ) : /* IGNORED: double width, single high*/ break; + case TY_ESC_DE('8' ) : scr->helpAlign ( ); break; + + case TY_CSI_PS('K', 0) : scr->clearToEndOfLine ( ); break; + case TY_CSI_PS('K', 1) : scr->clearToBeginOfLine ( ); break; + case TY_CSI_PS('K', 2) : scr->clearEntireLine ( ); break; + case TY_CSI_PS('J', 0) : scr->clearToEndOfScreen ( ); break; + case TY_CSI_PS('J', 1) : scr->clearToBeginOfScreen ( ); break; + case TY_CSI_PS('J', 2) : scr->clearEntireScreen ( ); break; + case TY_CSI_PS('g', 0) : scr->changeTabStop (FALSE ); break; //VT100 + case TY_CSI_PS('g', 3) : scr->clearTabStops ( ); break; //VT100 + case TY_CSI_PS('h', 4) : scr-> setMode (MODE_Insert ); break; + case TY_CSI_PS('h', 20) : setMode (MODE_NewLine ); break; + case TY_CSI_PS('i', 0) : /* IGNORE: attached printer */ break; //VT100 + case TY_CSI_PS('l', 4) : scr-> resetMode (MODE_Insert ); break; + case TY_CSI_PS('l', 20) : resetMode (MODE_NewLine ); break; + + case TY_CSI_PS('m', 0) : scr->setDefaultRendition ( ); break; + case TY_CSI_PS('m', 1) : scr-> setRendition (RE_BOLD ); break; //VT100 + case TY_CSI_PS('m', 4) : scr-> setRendition (RE_UNDERLINE); break; //VT100 + case TY_CSI_PS('m', 5) : scr-> setRendition (RE_BLINK ); break; //VT100 + case TY_CSI_PS('m', 7) : scr-> setRendition (RE_REVERSE ); break; + case TY_CSI_PS('m', 10) : /* IGNORED: mapping related */ break; //LINUX + case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX + case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX + case TY_CSI_PS('m', 22) : scr->resetRendition (RE_BOLD ); break; + case TY_CSI_PS('m', 24) : scr->resetRendition (RE_UNDERLINE); break; + case TY_CSI_PS('m', 25) : scr->resetRendition (RE_BLINK ); break; + case TY_CSI_PS('m', 27) : scr->resetRendition (RE_REVERSE ); break; + + case TY_CSI_PS('m', 30) : scr->setForeColor ( 0); break; + case TY_CSI_PS('m', 31) : scr->setForeColor ( 1); break; + case TY_CSI_PS('m', 32) : scr->setForeColor ( 2); break; + case TY_CSI_PS('m', 33) : scr->setForeColor ( 3); break; + case TY_CSI_PS('m', 34) : scr->setForeColor ( 4); break; + case TY_CSI_PS('m', 35) : scr->setForeColor ( 5); break; + case TY_CSI_PS('m', 36) : scr->setForeColor ( 6); break; + case TY_CSI_PS('m', 37) : scr->setForeColor ( 7); break; + case TY_CSI_PS('m', 39) : scr->setForeColorToDefault( ); break; + + case TY_CSI_PS('m', 40) : scr->setBackColor ( 0); break; + case TY_CSI_PS('m', 41) : scr->setBackColor ( 1); break; + case TY_CSI_PS('m', 42) : scr->setBackColor ( 2); break; + case TY_CSI_PS('m', 43) : scr->setBackColor ( 3); break; + case TY_CSI_PS('m', 44) : scr->setBackColor ( 4); break; + case TY_CSI_PS('m', 45) : scr->setBackColor ( 5); break; + case TY_CSI_PS('m', 46) : scr->setBackColor ( 6); break; + case TY_CSI_PS('m', 47) : scr->setBackColor ( 7); break; + case TY_CSI_PS('m', 49) : scr->setBackColorToDefault( ); break; + + case TY_CSI_PS('m', 90) : scr->setForeColor ( 8); break; + case TY_CSI_PS('m', 91) : scr->setForeColor ( 9); break; + case TY_CSI_PS('m', 92) : scr->setForeColor ( 10); break; + case TY_CSI_PS('m', 93) : scr->setForeColor ( 11); break; + case TY_CSI_PS('m', 94) : scr->setForeColor ( 12); break; + case TY_CSI_PS('m', 95) : scr->setForeColor ( 13); break; + case TY_CSI_PS('m', 96) : scr->setForeColor ( 14); break; + case TY_CSI_PS('m', 97) : scr->setForeColor ( 15); break; + + case TY_CSI_PS('m', 100) : scr->setBackColor ( 8); break; + case TY_CSI_PS('m', 101) : scr->setBackColor ( 9); break; + case TY_CSI_PS('m', 102) : scr->setBackColor ( 10); break; + case TY_CSI_PS('m', 103) : scr->setBackColor ( 11); break; + case TY_CSI_PS('m', 104) : scr->setBackColor ( 12); break; + case TY_CSI_PS('m', 105) : scr->setBackColor ( 13); break; + case TY_CSI_PS('m', 106) : scr->setBackColor ( 14); break; + case TY_CSI_PS('m', 107) : scr->setBackColor ( 15); break; + + case TY_CSI_PS('n', 5) : reportStatus ( ); break; + case TY_CSI_PS('n', 6) : reportCursorPosition ( ); break; + case TY_CSI_PS('q', 0) : /* IGNORED: LEDs off */ break; //VT100 + case TY_CSI_PS('q', 1) : /* IGNORED: LED1 on */ break; //VT100 + case TY_CSI_PS('q', 2) : /* IGNORED: LED2 on */ break; //VT100 + case TY_CSI_PS('q', 3) : /* IGNORED: LED3 on */ break; //VT100 + case TY_CSI_PS('q', 4) : /* IGNORED: LED4 on */ break; //VT100 + case TY_CSI_PS('x', 0) : reportTerminalParms ( 2); break; //VT100 + case TY_CSI_PS('x', 1) : reportTerminalParms ( 3); break; //VT100 + + case TY_CSI_PN('@' ) : scr->insertChars (p ); break; + case TY_CSI_PN('A' ) : scr->cursorUp (p ); break; //VT100 + case TY_CSI_PN('B' ) : scr->cursorDown (p ); break; //VT100 + case TY_CSI_PN('C' ) : scr->cursorRight (p ); break; //VT100 + case TY_CSI_PN('D' ) : scr->cursorLeft (p ); break; //VT100 + case TY_CSI_PN('G' ) : scr->setCursorX (p ); break; //LINUX + case TY_CSI_PN('H' ) : scr->setCursorYX (p, q); break; //VT100 + case TY_CSI_PN('L' ) : scr->insertLines (p ); break; + case TY_CSI_PN('M' ) : scr->deleteLines (p ); break; + case TY_CSI_PN('P' ) : scr->deleteChars (p ); break; + case TY_CSI_PN('X' ) : scr->eraseChars (p ); break; + case TY_CSI_PN('c' ) : reportTerminalType ( ); break; //VT100 + case TY_CSI_PN('d' ) : scr->setCursorY (p ); break; //LINUX + case TY_CSI_PN('f' ) : scr->setCursorYX (p, q); break; //VT100 + case TY_CSI_PN('r' ) : scr->setMargins (p, q); break; //VT100 + case TY_CSI_PN('y' ) : /* IGNORED: Confidence test */ break; //VT100 + + case TY_CSI_PR('h', 1) : setMode (MODE_AppCuKeys); break; //VT100 + case TY_CSI_PR('l', 1) : resetMode (MODE_AppCuKeys); break; //VT100 + case TY_CSI_PR('s', 1) : saveMode (MODE_AppCuKeys); break; //FIXME + case TY_CSI_PR('r', 1) : restoreMode (MODE_AppCuKeys); break; //FIXME + + case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100 + + case TY_CSI_PR('h', 3) : setColumns ( 132); break; //VT100 + case TY_CSI_PR('l', 3) : setColumns ( 80); break; //VT100 + + case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100 + case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100 + + case TY_CSI_PR('h', 5) : scr-> setMode (MODE_Screen ); break; //VT100 + case TY_CSI_PR('l', 5) : scr-> resetMode (MODE_Screen ); break; //VT100 + + case TY_CSI_PR('h', 6) : scr-> setMode (MODE_Origin ); break; //VT100 + case TY_CSI_PR('l', 6) : scr-> resetMode (MODE_Origin ); break; //VT100 + case TY_CSI_PR('s', 6) : scr-> saveMode (MODE_Origin ); break; //FIXME + case TY_CSI_PR('r', 6) : scr->restoreMode (MODE_Origin ); break; //FIXME + + case TY_CSI_PR('h', 7) : scr-> setMode (MODE_Wrap ); break; //VT100 + case TY_CSI_PR('l', 7) : scr-> resetMode (MODE_Wrap ); break; //VT100 + case TY_CSI_PR('s', 7) : scr-> saveMode (MODE_Wrap ); break; //FIXME + case TY_CSI_PR('r', 7) : scr->restoreMode (MODE_Wrap ); break; //FIXME + + case TY_CSI_PR('h', 8) : /* IGNORED: autorepeat on */ break; //VT100 + case TY_CSI_PR('l', 8) : /* IGNORED: autorepeat off */ break; //VT100 + + case TY_CSI_PR('h', 9) : /* IGNORED: interlace */ break; //VT100 + case TY_CSI_PR('l', 9) : /* IGNORED: interlace */ break; //VT100 + + case TY_CSI_PR('h', 25) : setMode (MODE_Cursor ); break; //VT100 + case TY_CSI_PR('l', 25) : resetMode (MODE_Cursor ); break; //VT100 + + case TY_CSI_PR('h', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM + case TY_CSI_PR('l', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM + case TY_CSI_PR('s', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM + case TY_CSI_PR('r', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM + + case TY_CSI_PR('h', 47) : setMode (MODE_AppScreen); break; //VT100 + case TY_CSI_PR('l', 47) : resetMode (MODE_AppScreen); break; //VT100 + + case TY_CSI_PR('h', 1000) : setMode (MODE_Mouse1000); break; //XTERM + case TY_CSI_PR('l', 1000) : resetMode (MODE_Mouse1000); break; //XTERM + case TY_CSI_PR('s', 1000) : saveMode (MODE_Mouse1000); break; //XTERM + case TY_CSI_PR('r', 1000) : restoreMode (MODE_Mouse1000); break; //XTERM + + case TY_CSI_PR('h', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM + case TY_CSI_PR('l', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM + case TY_CSI_PR('s', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM + case TY_CSI_PR('r', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM + + case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM + case TY_CSI_PR('l', 1047) : resetMode (MODE_AppScreen); break; //XTERM + + //FIXME: Unitoken: save translations + case TY_CSI_PR('h', 1048) : saveCursor ( ); break; //XTERM + case TY_CSI_PR('l', 1048) : restoreCursor ( ); break; //XTERM + + //FIXME: every once new sequences like this pop up in xterm. + // Here's a guess of what they could mean. + case TY_CSI_PR('h', 1049) : setMode (MODE_AppScreen); break; //XTERM + case TY_CSI_PR('l', 1049) : resetMode (MODE_AppScreen); break; //XTERM + + //FIXME: when changing between vt52 and ansi mode evtl do some resetting. + case TY_VT52__('A' ) : scr->cursorUp ( 1); break; //VT52 + case TY_VT52__('B' ) : scr->cursorDown ( 1); break; //VT52 + case TY_VT52__('C' ) : scr->cursorRight ( 1); break; //VT52 + case TY_VT52__('D' ) : scr->cursorLeft ( 1); break; //VT52 + + case TY_VT52__('F' ) : setAndUseCharset (0, '0'); break; //VT52 + case TY_VT52__('G' ) : setAndUseCharset (0, 'B'); break; //VT52 + + case TY_VT52__('H' ) : scr->setCursorYX (1,1 ); break; //VT52 + case TY_VT52__('I' ) : scr->reverseIndex ( ); break; //VT52 + case TY_VT52__('J' ) : scr->clearToEndOfScreen ( ); break; //VT52 + case TY_VT52__('K' ) : scr->clearToEndOfLine ( ); break; //VT52 + case TY_VT52__('Y' ) : scr->setCursorYX (p-31,q-31 ); break; //VT52 + case TY_VT52__('Z' ) : reportTerminalType ( ); break; //VT52 + case TY_VT52__('<' ) : setMode (MODE_Ansi ); break; //VT52 + case TY_VT52__('=' ) : setMode (MODE_AppKeyPad); break; //VT52 + case TY_VT52__('>' ) : resetMode (MODE_AppKeyPad); break; //VT52 + + default : ReportErrorToken(); break; + }; +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Terminal to Host protocol */ +/* */ +/* ------------------------------------------------------------------------- */ + +/* + Outgoing bytes originate from several sources: + + - Replies to Enquieries. + - Mouse Events + - Keyboard Events +*/ + +/*! +*/ + +void Vt102Emulation::sendString(const char* s) +{ + QByteArray tmp; + tmp.setRawData( s, strlen( s )); + emit sndBlock( tmp); +} + +void Vt102Emulation::sendString(const QByteArray s) +{ + emit sndBlock( s ); +} + +// Replies ----------------------------------------------------------------- -- + +// This section copes with replies send as response to an enquiery control code. + +/*! +*/ + +void Vt102Emulation::reportCursorPosition() +{ char tmp[20]; + sprintf(tmp,"\033[%d;%dR",scr->getCursorY()+1,scr->getCursorX()+1); + sendString(tmp); +} + +/* + What follows here is rather obsolete and faked stuff. + The correspondent enquieries are neverthenless issued. +*/ + +/*! +*/ + +void Vt102Emulation::reportTerminalType() +{ +//FIXME: should change? + if (getMode(MODE_Ansi)) +// sendString("\033[?1;2c"); // I'm a VT100 with AP0 //FIXME: send only in response to ^[[0c + sendString("\033[>0;115;0c"); // I'm a VT220 //FIXME: send only in response to ^[[>c + else + sendString("\033/Z"); // I'm a VT52 +} + +void Vt102Emulation::reportTerminalParms(int p) +// DECREPTPARM +{ char tmp[100]; + sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true. + sendString(tmp); +} + +/*! +*/ + +void Vt102Emulation::reportStatus() +{ + sendString("\033[0n"); //VT100. Device status report. 0 = Ready. +} + +/*! +*/ + +#define ANSWER_BACK "" // This is really obsolete VT100 stuff. + +void Vt102Emulation::reportAnswerBack() +{ + sendString(ANSWER_BACK); +} + +// Mouse Handling ---------------------------------------------------------- -- + +/*! + Mouse clicks are possibly reported to the client + application if it has issued interest in them. + They are normally consumed by the widget for copy + and paste, but may be propagated from the widget + when gui->setMouseMarks is set via setMode(MODE_Mouse1000). + + `x',`y' are 1-based. + `ev' (event) indicates the button pressed (0-2) + or a general mouse release (3). +*/ + +void Vt102Emulation::onMouse( int cb, int cx, int cy ) +{ char tmp[20]; + if (!connected) return; + sprintf(tmp,"\033[M%c%c%c",cb+040,cx+040,cy+040); + sendString(tmp); +} + +// Keyboard Handling ------------------------------------------------------- -- + +#define encodeMode(M,B) BITS(B,getMode(M)) +#define encodeStat(M,B) BITS(B,((ev->state() & (M)) == (M))) + +/* + Keyboard event handling has been simplified somewhat by pushing + the complications towards a configuration file [see KeyTrans class]. +*/ + +void Vt102Emulation::onKeyPress( QKeyEvent* ev ) +{ + if (!connected) return; // someone else gets the keys + +//printf("State/Key: 0x%04x 0x%04x (%d,%d)\n",ev->state(),ev->key(),ev->text().length(),ev->text().length()?ev->text().ascii()[0]:0); + + // revert to non-history when typing + if (scr->getHistCursor() != scr->getHistLines()); + scr->setHistCursor(scr->getHistLines()); + + // lookup in keyboard translation table ... + int cmd; const char* txt; int len; + if (keytrans->findEntry(ev->key(), encodeMode(MODE_NewLine , BITS_NewLine ) + // OLD, + encodeMode(MODE_Ansi , BITS_Ansi ) + // OBSOLETE, + encodeMode(MODE_AppCuKeys, BITS_AppCuKeys ) + // VT100 stuff + encodeStat(ControlButton , BITS_Control ) + + encodeStat(ShiftButton , BITS_Shift ) + + encodeStat(AltButton , BITS_Alt ), + &cmd, &txt, &len )) +//printf("cmd: %d, %s, %d\n",cmd,txt,len); + { + switch(cmd) // ... and execute if found. + { + case CMD_emitSelection : gui->emitSelection(); return; + case CMD_scrollPageUp : gui->doScroll(-gui->Lines()/2); return; + case CMD_scrollPageDown : gui->doScroll(+gui->Lines()/2); return; + case CMD_scrollLineUp : gui->doScroll(-1 ); return; + case CMD_scrollLineDown : gui->doScroll(+1 ); return; + case CMD_send : sendString( txt ); return; + case CMD_prevSession : emit prevSession(); return; + case CMD_nextSession : emit nextSession(); return; + } + } + // fall back handling + if (!ev->text().isEmpty()) + { + if (ev->state() & AltButton) sendString("\033"); // ESC, this is the ALT prefix + /// very hacky + if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='A')) sendString("\01"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='B')) sendString("\02"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='C')) sendString("\03"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='D')) sendString("\04"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='E')) sendString("\05"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='F')) sendString("\06"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='G')) sendString("\07"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='H')) sendString("\010"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='I')) sendString("\011"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='J')) sendString("\012"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='K')) sendString("\013"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='L')) sendString("\014"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='M')) sendString("\015"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='N')) sendString("\016"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='O')) sendString("\017"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='P')) sendString("\020"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='Q')) sendString("\021"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='R')) sendString("\022"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='S')) sendString("\023"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='T')) sendString("\024"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='U')) sendString("\025"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='V')) sendString("\026"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='W')) sendString("\027"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='X')) sendString("\030"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='Y')) sendString("\031"); + else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='Z')) sendString("\032"); + else + { + QCString s = codec->fromUnicode(ev->text()); // encode for application + sendString( s ); // we may well have s.length() > 1 + } + return; + } +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* VT100 Charsets */ +/* */ +/* ------------------------------------------------------------------------- */ + +// Character Set Conversion ------------------------------------------------ -- + +/* + The processing contains a VT100 specific code translation layer. + It's still in use and mainly responsible for the line drawing graphics. + + These and some other glyphs are assigned to codes (0x5f-0xfe) + normally occupied by the latin letters. Since this codes also + appear within control sequences, the extra code conversion + does not permute with the tokenizer and is placed behind it + in the pipeline. It only applies to tokens, which represent + plain characters. + + This conversion it eventually continued in TEWidget.C, since + it might involve VT100 enhanced fonts, which have these + particular glyphs allocated in (0x00-0x1f) in their code page. +*/ + +#define CHARSET charset[scr==screen[1]] + +// Apply current character map. + +unsigned short Vt102Emulation::applyCharset(unsigned short c) +{ + if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c-0x5f]; + if (CHARSET.pound && c == '#' ) return 0xa3; //This mode is obsolete + return c; +} + +/* + "Charset" related part of the emulation state. + This configures the VT100 charset filter. + + While most operation work on the current screen, + the following two are different. +*/ + +void Vt102Emulation::resetCharset(int scrno) +{ + charset[scrno].cu_cs = 0; + strncpy(charset[scrno].charset,"BBBB",4); + charset[scrno].sa_graphic = FALSE; + charset[scrno].sa_pound = FALSE; + charset[scrno].graphic = FALSE; + charset[scrno].pound = FALSE; +} + +/*! +*/ + +void Vt102Emulation::setCharset(int n, int cs) // on both screens. +{ + charset[0].charset[n&3] = cs; useCharset(charset[0].cu_cs); + charset[1].charset[n&3] = cs; useCharset(charset[1].cu_cs); +} + +/*! +*/ + +void Vt102Emulation::setAndUseCharset(int n, int cs) +{ + CHARSET.charset[n&3] = cs; + useCharset(n&3); +} + +/*! +*/ + +void Vt102Emulation::useCharset(int n) +{ + CHARSET.cu_cs = n&3; + CHARSET.graphic = (CHARSET.charset[n&3] == '0'); + CHARSET.pound = (CHARSET.charset[n&3] == 'A'); //This mode is obsolete +} + +/*! Save the cursor position and the rendition attribute settings. */ + +void Vt102Emulation::saveCursor() +{ + CHARSET.sa_graphic = CHARSET.graphic; + CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete + // we are not clear about these + //sa_charset = charsets[cScreen->charset]; + //sa_charset_num = cScreen->charset; + scr->saveCursor(); +} + +/*! Restore the cursor position and the rendition attribute settings. */ + +void Vt102Emulation::restoreCursor() +{ + CHARSET.graphic = CHARSET.sa_graphic; + CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete + scr->restoreCursor(); +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Mode Operations */ +/* */ +/* ------------------------------------------------------------------------- */ + +/* + Some of the emulations state is either added to the state of the screens. + + This causes some scoping problems, since different emulations choose to + located the mode either to the current screen or to both. + + For strange reasons, the extend of the rendition attributes ranges over + all screens and not over the actual screen. + + We decided on the precise precise extend, somehow. +*/ + +// "Mode" related part of the state. These are all booleans. + +void Vt102Emulation::resetModes() +{ + resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000); + resetMode(MODE_AppScreen); saveMode(MODE_AppScreen); + // here come obsolete modes + resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys); + resetMode(MODE_NewLine ); + setMode(MODE_Ansi ); +} + +void Vt102Emulation::setMode(int m) +{ + currParm.mode[m] = TRUE; + switch (m) + { + case MODE_Mouse1000 : gui->setMouseMarks(FALSE); + break; + case MODE_AppScreen : screen[1]->clearSelection(); + screen[1]->clearEntireScreen(); + setScreen(1); + break; + } + if (m < MODES_SCREEN || m == MODE_NewLine) + { + screen[0]->setMode(m); + screen[1]->setMode(m); + } +} + +void Vt102Emulation::resetMode(int m) +{ + currParm.mode[m] = FALSE; + switch (m) + { + case MODE_Mouse1000 : gui->setMouseMarks(TRUE); + break; + case MODE_AppScreen : screen[0]->clearSelection(); + setScreen(0); + break; + } + if (m < MODES_SCREEN || m == MODE_NewLine) + { + screen[0]->resetMode(m); + screen[1]->resetMode(m); + } +} + +void Vt102Emulation::saveMode(int m) +{ + saveParm.mode[m] = currParm.mode[m]; +} + +void Vt102Emulation::restoreMode(int m) +{ + if(saveParm.mode[m]) setMode(m); else resetMode(m); +} + +BOOL Vt102Emulation::getMode(int m) +{ + return currParm.mode[m]; +} + +void Vt102Emulation::setConnect(bool c) +{ + EmulationLayer::setConnect(c); + if (c) + { // refresh mouse mode + if (getMode(MODE_Mouse1000)) + setMode(MODE_Mouse1000); + else + resetMode(MODE_Mouse1000); + } +} + +/* ------------------------------------------------------------------------- */ +/* */ +/* Diagnostic */ +/* */ +/* ------------------------------------------------------------------------- */ + +/*! shows the contents of the scan buffer. + + This functions is used for diagnostics. It is called by \e ReportErrorToken + to inform about strings that cannot be decoded or handled by the emulation. + + \sa ReportErrorToken +*/ + +/*! +*/ + +static void hexdump(int* s, int len) +{ int i; + for (i = 0; i < len; i++) + { + if (s[i] == '\\') + printf("\\\\"); + else + if ((s[i]) > 32 && s[i] < 127) + printf("%c",s[i]); + else + printf("\\%04x(hex)",s[i]); + } +} + +void Vt102Emulation::scan_buffer_report() +{ + if (ppos == 0 || ppos == 1 && (pbuf[0] & 0xff) >= 32) return; + printf("token: "); hexdump(pbuf,ppos); printf("\n"); +} + +/*! +*/ + +void Vt102Emulation::ReportErrorToken() +{ + printf("undecodable "); scan_buffer_report(); +} diff --git a/noncore/apps/opie-console/vt102emulation.h b/noncore/apps/opie-console/vt102emulation.h new file mode 100644 index 0000000..018835e --- a/dev/null +++ b/noncore/apps/opie-console/vt102emulation.h @@ -0,0 +1,153 @@ +/* -------------------------------------------------------------------------- */ +/* */ +/* [TEmuVt102.h] X Terminal Emulation */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ +/* */ +/* This file is part of Konsole - an X terminal for KDE */ +/* */ +/* -------------------------------------------------------------------------- */ +/* */ +/* Ported Konsole to Qt/Embedded */ +/* */ +/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ +/* */ +/* -------------------------------------------------------------------------- */ +/* Ported embedded-konsole to opie-terminal */ +/* */ +/* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef VT102EMU_H +#define VT102EMU_H + +#include "widget.h" +#include "screen.h" +#include "emulation_layer.h" +#include <qtimer.h> +#include <stdio.h> + +// + +#define MODE_AppScreen (MODES_SCREEN+0) +#define MODE_AppCuKeys (MODES_SCREEN+1) +#define MODE_AppKeyPad (MODES_SCREEN+2) +#define MODE_Mouse1000 (MODES_SCREEN+3) +#define MODE_Ansi (MODES_SCREEN+4) +#define MODE_total (MODES_SCREEN+5) + +struct DECpar +{ + BOOL mode[MODE_total]; +}; + +struct CharCodes +{ + // coding info + char charset[4]; // + int cu_cs; // actual charset. + bool graphic; // Some VT100 tricks + bool pound ; // Some VT100 tricks + bool sa_graphic; // saved graphic + bool sa_pound; // saved pound +}; + +class Vt102Emulation: public EmulationLayer +{ Q_OBJECT + +public: + + Vt102Emulation(Widget* gui); + ~Vt102Emulation(); + +public slots: // signals incoming from Widget + + void onKeyPress(QKeyEvent*); + void onMouse(int cb, int cx, int cy); + +signals: + + void changeTitle(int,const QString&); + void prevSession(); + void nextSession(); + +public: + + void reset(); + + /** + * receive a char from IOLayer + */ + void onRcvChar(int cc); + + /** + * sends a list of bytes to the IOLayer + */ + void sendString(const QByteArray); + + /** + * @deprecated use QByteArray instead + * see sendString() above + */ + void sendString(const char *); + +public: + + BOOL getMode (int m); + + void setMode (int m); + void resetMode (int m); + void saveMode (int m); + void restoreMode(int m); + void resetModes(); + + void setConnect(bool r); + +private: + + void resetToken(); +#define MAXPBUF 80 + void pushToToken(int cc); + int pbuf[MAXPBUF]; //FIXME: overflow? + int ppos; +#define MAXARGS 15 + void addDigit(int dig); + void addArgument(); + int argv[MAXARGS]; + int argc; + void initTokenizer(); + int tbl[256]; + + void scan_buffer_report(); //FIXME: rename + void ReportErrorToken(); //FIXME: rename + + void tau(int code, int p, int q); + void XtermHack(); + + // + + void reportTerminalType(); + void reportStatus(); + void reportAnswerBack(); + void reportCursorPosition(); + void reportTerminalParms(int p); + +protected: + + unsigned short applyCharset(unsigned short c); + void setCharset(int n, int cs); + void useCharset(int n); + void setAndUseCharset(int n, int cs); + void saveCursor(); + void restoreCursor(); + void resetCharset(int scrno); + CharCodes charset[2]; + + DECpar currParm; + DECpar saveParm; +}; + +#endif // ifndef ANSIEMU_H diff --git a/noncore/apps/opie-console/vt102emulation.o b/noncore/apps/opie-console/vt102emulation.o Binary files differnew file mode 100644 index 0000000..009a4fa --- a/dev/null +++ b/noncore/apps/opie-console/vt102emulation.o |