-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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [emulation_layer.cpp] Terminal Emulation Decoder */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | /* */ | ||
19 | /* Modified to suit opie-console */ | ||
20 | /* */ | ||
21 | /* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ | ||
22 | /* */ | ||
23 | /* -------------------------------------------------------------------------- */ | ||
24 | |||
25 | /*! \class EmulationLayer | ||
26 | |||
27 | \brief Mediator between Widget and Screen. | ||
28 | |||
29 | This class is responsible to scan the escapes sequences of the terminal | ||
30 | emulation and to map it to their corresponding semantic complements. | ||
31 | Thus this module knows mainly about decoding escapes sequences and | ||
32 | is a stateless device w.r.t. the semantics. | ||
33 | |||
34 | It is also responsible to refresh the Widget by certain rules. | ||
35 | |||
36 | \sa Widget \sa Screen | ||
37 | |||
38 | \par A note on refreshing | ||
39 | |||
40 | Although the modifications to the current screen image could immediately | ||
41 | be propagated via `Widget' to the graphical surface, we have chosen | ||
42 | another way here. | ||
43 | |||
44 | The reason for doing so is twofold. | ||
45 | |||
46 | First, experiments show that directly displaying the operation results | ||
47 | in slowing down the overall performance of emulations. Displaying | ||
48 | individual characters using X11 creates a lot of overhead. | ||
49 | |||
50 | Second, by using the following refreshing method, the screen operations | ||
51 | can be completely separated from the displaying. This greatly simplifies | ||
52 | the programmer's task of coding and maintaining the screen operations, | ||
53 | since one need not worry about differential modifications on the | ||
54 | display affecting the operation of concern. | ||
55 | |||
56 | We use a refreshing algorithm here that has been adoped from rxvt/kvt. | ||
57 | |||
58 | By this, refreshing is driven by a timer, which is (re)started whenever | ||
59 | a new bunch of data to be interpreted by the emulation arives at `onRcvBlock'. | ||
60 | As soon as no more data arrive for `BULK_TIMEOUT' milliseconds, we trigger | ||
61 | refresh. This rule suits both bulk display operation as done by curses as | ||
62 | well as individual characters typed. | ||
63 | (BULK_TIMEOUT < 1000 / max characters received from keyboard per second). | ||
64 | |||
65 | Additionally, we trigger refreshing by newlines comming in to make visual | ||
66 | snapshots of lists as produced by `cat', `ls' and likely programs, thereby | ||
67 | producing the illusion of a permanent and immediate display operation. | ||
68 | |||
69 | As a sort of catch-all needed for cases where none of the above | ||
70 | conditions catch, the screen refresh is also triggered by a count | ||
71 | of incoming bulks (`bulk_incnt'). | ||
72 | */ | ||
73 | |||
74 | /* FIXME | ||
75 | - evtl. the bulk operations could be made more transparent. | ||
76 | */ | ||
77 | |||
78 | #include "emulation_layer.h" | ||
79 | #include "widget.h" | ||
80 | #include "screen.h" | ||
81 | #include <stdio.h> | ||
82 | #include <stdlib.h> | ||
83 | #include <unistd.h> | ||
84 | #include <qkeycode.h> | ||
85 | |||
86 | |||
87 | /* ------------------------------------------------------------------------- */ | ||
88 | /* */ | ||
89 | /* EmulationLayer */ | ||
90 | /* */ | ||
91 | /* ------------------------------------------------------------------------- */ | ||
92 | |||
93 | #define CNTL(c) ((c)-'@') | ||
94 | |||
95 | /*! | ||
96 | */ | ||
97 | |||
98 | EmulationLayer::EmulationLayer(Widget* gui) | ||
99 | : decoder((QTextDecoder*)NULL) | ||
100 | { | ||
101 | this->gui = gui; | ||
102 | |||
103 | screen[0] = new Screen(gui->Lines(),gui->Columns()); | ||
104 | screen[1] = new Screen(gui->Lines(),gui->Columns()); | ||
105 | scr = screen[0]; | ||
106 | |||
107 | bulk_nlcnt = 0; // reset bulk newline counter | ||
108 | bulk_incnt = 0; // reset bulk counter | ||
109 | connected = FALSE; | ||
110 | |||
111 | QObject::connect(&bulk_timer, SIGNAL(timeout()), this, SLOT(showBulk()) ); | ||
112 | QObject::connect(gui,SIGNAL(changedImageSizeSignal(int,int)), | ||
113 | this,SLOT(onImageSizeChange(int,int))); | ||
114 | QObject::connect(gui,SIGNAL(changedHistoryCursor(int)), | ||
115 | this,SLOT(onHistoryCursorChange(int))); | ||
116 | QObject::connect(gui,SIGNAL(keyPressedSignal(QKeyEvent*)), | ||
117 | this,SLOT(onKeyPress(QKeyEvent*))); | ||
118 | QObject::connect(gui,SIGNAL(beginSelectionSignal(const int,const int)), | ||
119 | this,SLOT(onSelectionBegin(const int,const int)) ); | ||
120 | QObject::connect(gui,SIGNAL(extendSelectionSignal(const int,const int)), | ||
121 | this,SLOT(onSelectionExtend(const int,const int)) ); | ||
122 | QObject::connect(gui,SIGNAL(endSelectionSignal(const BOOL)), | ||
123 | this,SLOT(setSelection(const BOOL)) ); | ||
124 | QObject::connect(gui,SIGNAL(clearSelectionSignal()), | ||
125 | this,SLOT(clearSelection()) ); | ||
126 | } | ||
127 | |||
128 | /*! | ||
129 | */ | ||
130 | |||
131 | EmulationLayer::~EmulationLayer() | ||
132 | { | ||
133 | delete screen[0]; | ||
134 | delete screen[1]; | ||
135 | bulk_timer.stop(); | ||
136 | } | ||
137 | |||
138 | /*! change between primary and alternate screen | ||
139 | */ | ||
140 | |||
141 | void EmulationLayer::setScreen(int n) | ||
142 | { | ||
143 | scr = screen[n&1]; | ||
144 | } | ||
145 | |||
146 | void EmulationLayer::setHistory(bool on) | ||
147 | { | ||
148 | screen[0]->setScroll(on); | ||
149 | if (!connected) return; | ||
150 | showBulk(); | ||
151 | } | ||
152 | |||
153 | bool EmulationLayer::history() | ||
154 | { | ||
155 | return screen[0]->hasScroll(); | ||
156 | } | ||
157 | |||
158 | void EmulationLayer::setCodec(int c) | ||
159 | { | ||
160 | //FIXME: check whether we have to free codec | ||
161 | codec = c ? QTextCodec::codecForName("utf8") | ||
162 | : QTextCodec::codecForLocale(); | ||
163 | if (decoder) delete decoder; | ||
164 | decoder = codec->makeDecoder(); | ||
165 | } | ||
166 | |||
167 | void EmulationLayer::setKeytrans(int no) | ||
168 | { | ||
169 | keytrans = KeyTrans::find(no); | ||
170 | } | ||
171 | |||
172 | void EmulationLayer::setKeytrans(const char * no) | ||
173 | { | ||
174 | keytrans = KeyTrans::find(no); | ||
175 | } | ||
176 | |||
177 | // Interpreting Codes --------------------------------------------------------- | ||
178 | |||
179 | /* | ||
180 | This section deals with decoding the incoming character stream. | ||
181 | Decoding means here, that the stream is first seperated into `tokens' | ||
182 | which are then mapped to a `meaning' provided as operations by the | ||
183 | `Screen' class. | ||
184 | */ | ||
185 | |||
186 | /*! | ||
187 | */ | ||
188 | |||
189 | void EmulationLayer::onRcvChar(int c) | ||
190 | // process application unicode input to terminal | ||
191 | // this is a trivial scanner | ||
192 | { | ||
193 | c &= 0xff; | ||
194 | switch (c) | ||
195 | { | ||
196 | case '\b' : scr->BackSpace(); break; | ||
197 | case '\t' : scr->Tabulate(); break; | ||
198 | case '\n' : scr->NewLine(); break; | ||
199 | case '\r' : scr->Return(); break; | ||
200 | case 0x07 : gui->Bell(); break; | ||
201 | default : scr->ShowCharacter(c); break; | ||
202 | }; | ||
203 | } | ||
204 | |||
205 | /* ------------------------------------------------------------------------- */ | ||
206 | /* */ | ||
207 | /* Keyboard Handling */ | ||
208 | /* */ | ||
209 | /* ------------------------------------------------------------------------- */ | ||
210 | |||
211 | /*! | ||
212 | */ | ||
213 | |||
214 | void EmulationLayer::onKeyPress( QKeyEvent* ev ) | ||
215 | { | ||
216 | if (!connected) return; // someone else gets the keys | ||
217 | if (scr->getHistCursor() != scr->getHistLines()); | ||
218 | scr->setHistCursor(scr->getHistLines()); | ||
219 | if (!ev->text().isEmpty()) | ||
220 | { // A block of text | ||
221 | // Note that the text is proper unicode. | ||
222 | // We should do a conversion here, but since this | ||
223 | // routine will never be used, we simply emit plain ascii. | ||
224 | sendString( ev->text().ascii() ); //,ev->text().length()); | ||
225 | } | ||
226 | else if (ev->ascii()>0) | ||
227 | { | ||
228 | QByteArray c = QByteArray( 1 ); | ||
229 | c.at( 0 ) = ev->ascii(); | ||
230 | // ibot: qbytearray is emited not char* | ||
231 | emit sndBlock( (QByteArray) c ); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | // Unblocking, Byte to Unicode translation --------------------------------- -- | ||
236 | |||
237 | /* | ||
238 | We are doing code conversion from locale to unicode first. | ||
239 | */ | ||
240 | |||
241 | void EmulationLayer::onRcvBlock(const QByteArray &s ) | ||
242 | { | ||
243 | bulkStart(); | ||
244 | bulk_incnt += 1; | ||
245 | for (int i = 0; i < s.size(); i++) | ||
246 | { | ||
247 | //TODO: ibot: maybe decoding qbytearray to unicode in io_layer? | ||
248 | QString result = decoder->toUnicode(&s[i],1); | ||
249 | int reslen = result.length(); | ||
250 | for (int j = 0; j < reslen; j++) | ||
251 | onRcvChar(result[j].unicode()); | ||
252 | if (s[i] == '\n') bulkNewline(); | ||
253 | } | ||
254 | bulkEnd(); | ||
255 | } | ||
256 | |||
257 | // Selection --------------------------------------------------------------- -- | ||
258 | |||
259 | void EmulationLayer::onSelectionBegin(const int x, const int y) { | ||
260 | if (!connected) return; | ||
261 | scr->setSelBeginXY(x,y); | ||
262 | showBulk(); | ||
263 | } | ||
264 | |||
265 | void EmulationLayer::onSelectionExtend(const int x, const int y) { | ||
266 | if (!connected) return; | ||
267 | scr->setSelExtentXY(x,y); | ||
268 | showBulk(); | ||
269 | } | ||
270 | |||
271 | void EmulationLayer::setSelection(const BOOL preserve_line_breaks) { | ||
272 | if (!connected) return; | ||
273 | QString t = scr->getSelText(preserve_line_breaks); | ||
274 | if (!t.isNull()) gui->setSelection(t); | ||
275 | } | ||
276 | |||
277 | void EmulationLayer::clearSelection() { | ||
278 | if (!connected) return; | ||
279 | scr->clearSelection(); | ||
280 | showBulk(); | ||
281 | } | ||
282 | |||
283 | // Refreshing -------------------------------------------------------------- -- | ||
284 | |||
285 | #define BULK_TIMEOUT 20 | ||
286 | |||
287 | /*! | ||
288 | called when \n comes in. Evtl. triggers showBulk at endBulk | ||
289 | */ | ||
290 | |||
291 | void EmulationLayer::bulkNewline() | ||
292 | { | ||
293 | bulk_nlcnt += 1; | ||
294 | bulk_incnt = 0; // reset bulk counter since `nl' rule applies | ||
295 | } | ||
296 | |||
297 | /*! | ||
298 | */ | ||
299 | |||
300 | void EmulationLayer::showBulk() | ||
301 | { | ||
302 | bulk_nlcnt = 0; // reset bulk newline counter | ||
303 | bulk_incnt = 0; // reset bulk counter | ||
304 | if (connected) | ||
305 | { | ||
306 | Character* image = scr->getCookedImage(); // get the image | ||
307 | gui->setImage(image, | ||
308 | scr->getLines(), | ||
309 | scr->getColumns()); // actual refresh | ||
310 | free(image); | ||
311 | //FIXME: check that we do not trigger other draw event here. | ||
312 | gui->setScroll(scr->getHistCursor(),scr->getHistLines()); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | void EmulationLayer::bulkStart() | ||
317 | { | ||
318 | if (bulk_timer.isActive()) bulk_timer.stop(); | ||
319 | } | ||
320 | |||
321 | void EmulationLayer::bulkEnd() | ||
322 | { | ||
323 | if ( bulk_nlcnt > gui->Lines() || bulk_incnt > 20 ) | ||
324 | showBulk(); // resets bulk_??cnt to 0, too. | ||
325 | else | ||
326 | bulk_timer.start(BULK_TIMEOUT,TRUE); | ||
327 | } | ||
328 | |||
329 | void EmulationLayer::setConnect(bool c) | ||
330 | { | ||
331 | connected = c; | ||
332 | if ( connected) | ||
333 | { | ||
334 | onImageSizeChange(gui->Lines(), gui->Columns()); | ||
335 | showBulk(); | ||
336 | } | ||
337 | else | ||
338 | { | ||
339 | scr->clearSelection(); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | // --------------------------------------------------------------------------- | ||
344 | |||
345 | /*! triggered by image size change of the Widget `gui'. | ||
346 | |||
347 | This event is simply propagated to the attached screens | ||
348 | and to the related serial line. | ||
349 | */ | ||
350 | |||
351 | void EmulationLayer::onImageSizeChange(int lines, int columns) | ||
352 | { | ||
353 | if (!connected) return; | ||
354 | screen[0]->resizeImage(lines,columns); | ||
355 | screen[1]->resizeImage(lines,columns); | ||
356 | showBulk(); | ||
357 | emit ImageSizeChanged(lines,columns); // propagate event to serial line | ||
358 | } | ||
359 | |||
360 | void EmulationLayer::onHistoryCursorChange(int cursor) | ||
361 | { | ||
362 | if (!connected) return; | ||
363 | scr->setHistCursor(cursor); | ||
364 | showBulk(); | ||
365 | } | ||
366 | |||
367 | void EmulationLayer::setColumns(int columns) | ||
368 | { | ||
369 | //FIXME: this goes strange ways. | ||
370 | // Can we put this straight or explain it at least? | ||
371 | emit changeColumns(columns); | ||
372 | } | ||
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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [TEmulation.cpp] Terminal Emulation Decoder */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | /* ------------------------------------------------------------------------- */ | ||
19 | /* */ | ||
20 | /* Modified to suit opie-console */ | ||
21 | /* */ | ||
22 | /* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ | ||
23 | /* */ | ||
24 | /* ------------------------------------------------------------------------- */ | ||
25 | |||
26 | /*! \class TEmulation | ||
27 | |||
28 | \brief Mediator between TEWidget and TEScreen. | ||
29 | |||
30 | This class is responsible to scan the escapes sequences of the terminal | ||
31 | emulation and to map it to their corresponding semantic complements. | ||
32 | Thus this module knows mainly about decoding escapes sequences and | ||
33 | is a stateless device w.r.t. the semantics. | ||
34 | |||
35 | It is also responsible to refresh the TEWidget by certain rules. | ||
36 | |||
37 | \sa TEWidget \sa TEScreen | ||
38 | |||
39 | \par A note on refreshing | ||
40 | |||
41 | Although the modifications to the current screen image could immediately | ||
42 | be propagated via `TEWidget' to the graphical surface, we have chosen | ||
43 | another way here. | ||
44 | |||
45 | The reason for doing so is twofold. | ||
46 | |||
47 | First, experiments show that directly displaying the operation results | ||
48 | in slowing down the overall performance of emulations. Displaying | ||
49 | individual characters using X11 creates a lot of overhead. | ||
50 | |||
51 | Second, by using the following refreshing method, the screen operations | ||
52 | can be completely separated from the displaying. This greatly simplifies | ||
53 | the programmer's task of coding and maintaining the screen operations, | ||
54 | since one need not worry about differential modifications on the | ||
55 | display affecting the operation of concern. | ||
56 | |||
57 | We use a refreshing algorithm here that has been adoped from rxvt/kvt. | ||
58 | |||
59 | By this, refreshing is driven by a timer, which is (re)started whenever | ||
60 | a new bunch of data to be interpreted by the emulation arives at `onRcvBlock'. | ||
61 | As soon as no more data arrive for `BULK_TIMEOUT' milliseconds, we trigger | ||
62 | refresh. This rule suits both bulk display operation as done by curses as | ||
63 | well as individual characters typed. | ||
64 | (BULK_TIMEOUT < 1000 / max characters received from keyboard per second). | ||
65 | |||
66 | Additionally, we trigger refreshing by newlines comming in to make visual | ||
67 | snapshots of lists as produced by `cat', `ls' and likely programs, thereby | ||
68 | producing the illusion of a permanent and immediate display operation. | ||
69 | |||
70 | As a sort of catch-all needed for cases where none of the above | ||
71 | conditions catch, the screen refresh is also triggered by a count | ||
72 | of incoming bulks (`bulk_incnt'). | ||
73 | */ | ||
74 | |||
75 | /* FIXME | ||
76 | - evtl. the bulk operations could be made more transparent. | ||
77 | */ | ||
78 | |||
79 | #include "emulation_layer.h" | ||
80 | #include "widget.h" | ||
81 | #include "TEScreen.h" | ||
82 | #include <stdio.h> | ||
83 | #include <stdlib.h> | ||
84 | #include <unistd.h> | ||
85 | #include <qkeycode.h> | ||
86 | |||
87 | |||
88 | /* ------------------------------------------------------------------------- */ | ||
89 | /* */ | ||
90 | /* EmulationLayer */ | ||
91 | /* */ | ||
92 | /* ------------------------------------------------------------------------- */ | ||
93 | |||
94 | #define CNTL(c) ((c)-'@') | ||
95 | |||
96 | /*! | ||
97 | */ | ||
98 | |||
99 | EmulationLayer::EmulationLayer(TEWidget* gui) | ||
100 | : decoder((QTextDecoder*)NULL) | ||
101 | { | ||
102 | this->gui = gui; | ||
103 | |||
104 | screen[0] = new TEScreen(gui->Lines(),gui->Columns()); | ||
105 | screen[1] = new TEScreen(gui->Lines(),gui->Columns()); | ||
106 | scr = screen[0]; | ||
107 | |||
108 | bulk_nlcnt = 0; // reset bulk newline counter | ||
109 | bulk_incnt = 0; // reset bulk counter | ||
110 | connected = FALSE; | ||
111 | |||
112 | QObject::connect(&bulk_timer, SIGNAL(timeout()), this, SLOT(showBulk()) ); | ||
113 | QObject::connect(gui,SIGNAL(changedImageSizeSignal(int,int)), | ||
114 | this,SLOT(onImageSizeChange(int,int))); | ||
115 | QObject::connect(gui,SIGNAL(changedHistoryCursor(int)), | ||
116 | this,SLOT(onHistoryCursorChange(int))); | ||
117 | QObject::connect(gui,SIGNAL(keyPressedSignal(QKeyEvent*)), | ||
118 | this,SLOT(onKeyPress(QKeyEvent*))); | ||
119 | QObject::connect(gui,SIGNAL(beginSelectionSignal(const int,const int)), | ||
120 | this,SLOT(onSelectionBegin(const int,const int)) ); | ||
121 | QObject::connect(gui,SIGNAL(extendSelectionSignal(const int,const int)), | ||
122 | this,SLOT(onSelectionExtend(const int,const int)) ); | ||
123 | QObject::connect(gui,SIGNAL(endSelectionSignal(const BOOL)), | ||
124 | this,SLOT(setSelection(const BOOL)) ); | ||
125 | QObject::connect(gui,SIGNAL(clearSelectionSignal()), | ||
126 | this,SLOT(clearSelection()) ); | ||
127 | } | ||
128 | |||
129 | /*! | ||
130 | */ | ||
131 | |||
132 | EmulationLayer::~EmulationLayer() | ||
133 | { | ||
134 | delete screen[0]; | ||
135 | delete screen[1]; | ||
136 | bulk_timer.stop(); | ||
137 | } | ||
138 | |||
139 | /*! change between primary and alternate screen | ||
140 | */ | ||
141 | |||
142 | void EmulationLayer::setScreen(int n) | ||
143 | { | ||
144 | scr = screen[n&1]; | ||
145 | } | ||
146 | |||
147 | void EmulationLayer::setHistory(bool on) | ||
148 | { | ||
149 | screen[0]->setScroll(on); | ||
150 | if (!connected) return; | ||
151 | showBulk(); | ||
152 | } | ||
153 | |||
154 | bool EmulationLayer::history() | ||
155 | { | ||
156 | return screen[0]->hasScroll(); | ||
157 | } | ||
158 | |||
159 | void EmulationLayer::setCodec(int c) | ||
160 | { | ||
161 | //FIXME: check whether we have to free codec | ||
162 | codec = c ? QTextCodec::codecForName("utf8") | ||
163 | : QTextCodec::codecForLocale(); | ||
164 | if (decoder) delete decoder; | ||
165 | decoder = codec->makeDecoder(); | ||
166 | } | ||
167 | |||
168 | void EmulationLayer::setKeytrans(int no) | ||
169 | { | ||
170 | keytrans = KeyTrans::find(no); | ||
171 | } | ||
172 | |||
173 | void EmulationLayer::setKeytrans(const char * no) | ||
174 | { | ||
175 | keytrans = KeyTrans::find(no); | ||
176 | } | ||
177 | |||
178 | // Interpreting Codes --------------------------------------------------------- | ||
179 | |||
180 | /* | ||
181 | This section deals with decoding the incoming character stream. | ||
182 | Decoding means here, that the stream is first seperated into `tokens' | ||
183 | which are then mapped to a `meaning' provided as operations by the | ||
184 | `Screen' class. | ||
185 | */ | ||
186 | |||
187 | /*! | ||
188 | */ | ||
189 | |||
190 | void EmulationLayer::onRcvChar(int c) | ||
191 | // process application unicode input to terminal | ||
192 | // this is a trivial scanner | ||
193 | { | ||
194 | c &= 0xff; | ||
195 | switch (c) | ||
196 | { | ||
197 | case '\b' : scr->BackSpace(); break; | ||
198 | case '\t' : scr->Tabulate(); break; | ||
199 | case '\n' : scr->NewLine(); break; | ||
200 | case '\r' : scr->Return(); break; | ||
201 | case 0x07 : gui->Bell(); break; | ||
202 | default : scr->ShowCharacter(c); break; | ||
203 | }; | ||
204 | } | ||
205 | |||
206 | /* ------------------------------------------------------------------------- */ | ||
207 | /* */ | ||
208 | /* Keyboard Handling */ | ||
209 | /* */ | ||
210 | /* ------------------------------------------------------------------------- */ | ||
211 | |||
212 | /*! | ||
213 | */ | ||
214 | |||
215 | void EmulationLayer::onKeyPress( QKeyEvent* ev ) | ||
216 | { | ||
217 | if (!connected) return; // someone else gets the keys | ||
218 | if (scr->getHistCursor() != scr->getHistLines()); | ||
219 | scr->setHistCursor(scr->getHistLines()); | ||
220 | if (!ev->text().isEmpty()) | ||
221 | { // A block of text | ||
222 | // Note that the text is proper unicode. | ||
223 | // We should do a conversion here, but since this | ||
224 | // routine will never be used, we simply emit plain ascii. | ||
225 | sendString( ev->text().ascii() ); //,ev->text().length()); | ||
226 | } | ||
227 | else if (ev->ascii()>0) | ||
228 | { | ||
229 | QByteArray c = QByteArray( 1 ); | ||
230 | c.at( 0 ) = ev->ascii(); | ||
231 | // ibot: qbytearray is emited not char* | ||
232 | emit sndBlock( (QByteArray) c ); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | // Unblocking, Byte to Unicode translation --------------------------------- -- | ||
237 | |||
238 | /* | ||
239 | We are doing code conversion from locale to unicode first. | ||
240 | */ | ||
241 | |||
242 | void EmulationLayer::onRcvBlock(const QByteArray &s ) | ||
243 | { | ||
244 | bulkStart(); | ||
245 | bulk_incnt += 1; | ||
246 | for (int i = 0; i < s.size(); i++) | ||
247 | { | ||
248 | //TODO: ibot: maybe decoding qbytearray to unicode in io_layer? | ||
249 | QString result = decoder->toUnicode(&s[i],1); | ||
250 | int reslen = result.length(); | ||
251 | for (int j = 0; j < reslen; j++) | ||
252 | onRcvChar(result[j].unicode()); | ||
253 | if (s[i] == '\n') bulkNewline(); | ||
254 | } | ||
255 | bulkEnd(); | ||
256 | } | ||
257 | |||
258 | // Selection --------------------------------------------------------------- -- | ||
259 | |||
260 | void EmulationLayer::onSelectionBegin(const int x, const int y) { | ||
261 | if (!connected) return; | ||
262 | scr->setSelBeginXY(x,y); | ||
263 | showBulk(); | ||
264 | } | ||
265 | |||
266 | void EmulationLayer::onSelectionExtend(const int x, const int y) { | ||
267 | if (!connected) return; | ||
268 | scr->setSelExtentXY(x,y); | ||
269 | showBulk(); | ||
270 | } | ||
271 | |||
272 | void EmulationLayer::setSelection(const BOOL preserve_line_breaks) { | ||
273 | if (!connected) return; | ||
274 | QString t = scr->getSelText(preserve_line_breaks); | ||
275 | if (!t.isNull()) gui->setSelection(t); | ||
276 | } | ||
277 | |||
278 | void EmulationLayer::clearSelection() { | ||
279 | if (!connected) return; | ||
280 | scr->clearSelection(); | ||
281 | showBulk(); | ||
282 | } | ||
283 | |||
284 | // Refreshing -------------------------------------------------------------- -- | ||
285 | |||
286 | #define BULK_TIMEOUT 20 | ||
287 | |||
288 | /*! | ||
289 | called when \n comes in. Evtl. triggers showBulk at endBulk | ||
290 | */ | ||
291 | |||
292 | void EmulationLayer::bulkNewline() | ||
293 | { | ||
294 | bulk_nlcnt += 1; | ||
295 | bulk_incnt = 0; // reset bulk counter since `nl' rule applies | ||
296 | } | ||
297 | |||
298 | /*! | ||
299 | */ | ||
300 | |||
301 | void EmulationLayer::showBulk() | ||
302 | { | ||
303 | bulk_nlcnt = 0; // reset bulk newline counter | ||
304 | bulk_incnt = 0; // reset bulk counter | ||
305 | if (connected) | ||
306 | { | ||
307 | ca* image = scr->getCookedImage(); // get the image | ||
308 | gui->setImage(image, | ||
309 | scr->getLines(), | ||
310 | scr->getColumns()); // actual refresh | ||
311 | free(image); | ||
312 | //FIXME: check that we do not trigger other draw event here. | ||
313 | gui->setScroll(scr->getHistCursor(),scr->getHistLines()); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | void EmulationLayer::bulkStart() | ||
318 | { | ||
319 | if (bulk_timer.isActive()) bulk_timer.stop(); | ||
320 | } | ||
321 | |||
322 | void EmulationLayer::bulkEnd() | ||
323 | { | ||
324 | if ( bulk_nlcnt > gui->Lines() || bulk_incnt > 20 ) | ||
325 | showBulk(); // resets bulk_??cnt to 0, too. | ||
326 | else | ||
327 | bulk_timer.start(BULK_TIMEOUT,TRUE); | ||
328 | } | ||
329 | |||
330 | void EmulationLayer::setConnect(bool c) | ||
331 | { | ||
332 | connected = c; | ||
333 | if ( connected) | ||
334 | { | ||
335 | onImageSizeChange(gui->Lines(), gui->Columns()); | ||
336 | showBulk(); | ||
337 | } | ||
338 | else | ||
339 | { | ||
340 | scr->clearSelection(); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | // --------------------------------------------------------------------------- | ||
345 | |||
346 | /*! triggered by image size change of the TEWidget `gui'. | ||
347 | |||
348 | This event is simply propagated to the attached screens | ||
349 | and to the related serial line. | ||
350 | */ | ||
351 | |||
352 | void EmulationLayer::onImageSizeChange(int lines, int columns) | ||
353 | { | ||
354 | if (!connected) return; | ||
355 | screen[0]->resizeImage(lines,columns); | ||
356 | screen[1]->resizeImage(lines,columns); | ||
357 | showBulk(); | ||
358 | emit ImageSizeChanged(lines,columns); // propagate event to serial line | ||
359 | } | ||
360 | |||
361 | void EmulationLayer::onHistoryCursorChange(int cursor) | ||
362 | { | ||
363 | if (!connected) return; | ||
364 | scr->setHistCursor(cursor); | ||
365 | showBulk(); | ||
366 | } | ||
367 | |||
368 | void EmulationLayer::setColumns(int columns) | ||
369 | { | ||
370 | //FIXME: this goes strange ways. | ||
371 | // Can we put this straight or explain it at least? | ||
372 | emit changeColumns(columns); | ||
373 | } | ||
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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [emulation.h] Fundamental Terminal Emulation */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | /* -------------------------------------------------------------------------- */ | ||
19 | /* */ | ||
20 | /* made to a layer between io_layer and widget */ | ||
21 | /* */ | ||
22 | /* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ | ||
23 | /* */ | ||
24 | /* -------------------------------------------------------------------------- */ | ||
25 | |||
26 | #ifndef EMULATION_LAYER_H | ||
27 | #define EMULATION_LAYER_H | ||
28 | |||
29 | #include "widget.h" | ||
30 | #include "screen.h" | ||
31 | #include <qtimer.h> | ||
32 | #include <stdio.h> | ||
33 | #include <qtextcodec.h> | ||
34 | #include "keytrans.h" | ||
35 | |||
36 | class EmulationLayer : public QObject | ||
37 | { Q_OBJECT | ||
38 | |||
39 | public: | ||
40 | |||
41 | EmulationLayer(Widget* gui); | ||
42 | ~EmulationLayer(); | ||
43 | |||
44 | public: | ||
45 | virtual void setHistory(bool on); | ||
46 | virtual bool history(); | ||
47 | |||
48 | public slots: // signals incoming from Widget | ||
49 | |||
50 | virtual void onImageSizeChange(int lines, int columns); | ||
51 | virtual void onHistoryCursorChange(int cursor); | ||
52 | virtual void onKeyPress(QKeyEvent*); | ||
53 | |||
54 | virtual void clearSelection(); | ||
55 | virtual void onSelectionBegin(const int x, const int y); | ||
56 | virtual void onSelectionExtend(const int x, const int y); | ||
57 | virtual void setSelection(const BOOL preserve_line_breaks); | ||
58 | |||
59 | public slots: // signals incoming from data source | ||
60 | |||
61 | /** | ||
62 | * to be called, when new data arrives | ||
63 | */ | ||
64 | void onRcvBlock(const QByteArray&); | ||
65 | |||
66 | signals: | ||
67 | |||
68 | /** | ||
69 | * will send data, encoded to suit emulation | ||
70 | */ | ||
71 | void sndBlock(const QByteArray&); | ||
72 | |||
73 | void ImageSizeChanged(int lines, int columns); | ||
74 | |||
75 | void changeColumns(int columns); | ||
76 | |||
77 | void changeTitle(int arg, const char* str); | ||
78 | |||
79 | |||
80 | public: | ||
81 | |||
82 | /** | ||
83 | * process single char (decode) | ||
84 | */ | ||
85 | virtual void onRcvChar(int); | ||
86 | |||
87 | virtual void setMode (int) = 0; | ||
88 | virtual void resetMode(int) = 0; | ||
89 | |||
90 | /** | ||
91 | * @deprecated use qbytearray instead | ||
92 | */ | ||
93 | virtual void sendString(const char*) = 0; | ||
94 | |||
95 | /** | ||
96 | * sends a string to IOLayer | ||
97 | * encodes to suit emulation before | ||
98 | */ | ||
99 | virtual void sendString(const QByteArray&) = 0; | ||
100 | |||
101 | virtual void setConnect(bool r); | ||
102 | void setColumns(int columns); | ||
103 | |||
104 | void setKeytrans(int no); | ||
105 | void setKeytrans(const char * no); | ||
106 | |||
107 | protected: | ||
108 | |||
109 | Widget* gui; | ||
110 | Screen* scr; // referes to one `screen' | ||
111 | Screen* screen[2]; // 0 = primary, 1 = alternate | ||
112 | void setScreen(int n); // set `scr' to `screen[n]' | ||
113 | |||
114 | bool connected; // communicate with widget | ||
115 | |||
116 | void setCodec(int c); // codec number, 0 = locale, 1=utf8 | ||
117 | |||
118 | QTextCodec* codec; | ||
119 | QTextCodec* localeCodec; | ||
120 | QTextDecoder* decoder; | ||
121 | |||
122 | KeyTrans* keytrans; | ||
123 | |||
124 | // refreshing related material. | ||
125 | // this is localized in the class. | ||
126 | private slots: // triggered by timer | ||
127 | |||
128 | void showBulk(); | ||
129 | |||
130 | private: | ||
131 | |||
132 | void bulkNewline(); | ||
133 | void bulkStart(); | ||
134 | void bulkEnd(); | ||
135 | |||
136 | private: | ||
137 | |||
138 | QTimer bulk_timer; | ||
139 | int bulk_nlcnt; // bulk newline counter | ||
140 | char* SelectedText; | ||
141 | int bulk_incnt; // bulk counter | ||
142 | |||
143 | |||
144 | }; | ||
145 | |||
146 | #endif // ifndef EMULATION_H | ||
diff --git a/noncore/apps/opie-console/emulation_layer.o b/noncore/apps/opie-console/emulation_layer.o new file mode 100644 index 0000000..fe80bcb --- a/dev/null +++ b/noncore/apps/opie-console/emulation_layer.o | |||
Binary files differ | |||
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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [history.c] History Buffer */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | /* */ | ||
19 | /* Ported embedded-Konsole to opie-console */ | ||
20 | /* */ | ||
21 | /* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ | ||
22 | /* */ | ||
23 | /* -------------------------------------------------------------------------- */ | ||
24 | |||
25 | #include "history.h" | ||
26 | #include <stdlib.h> | ||
27 | #include <assert.h> | ||
28 | #include <stdio.h> | ||
29 | #include <sys/types.h> | ||
30 | #include <unistd.h> | ||
31 | #include <errno.h> | ||
32 | |||
33 | #define HERE printf("%s(%d): here\n",__FILE__,__LINE__) | ||
34 | |||
35 | /* | ||
36 | An arbitrary long scroll. | ||
37 | |||
38 | One can modify the scroll only by adding either cells | ||
39 | or newlines, but access it randomly. | ||
40 | |||
41 | The model is that of an arbitrary wide typewriter scroll | ||
42 | in that the scroll is a serie of lines and each line is | ||
43 | a serie of cells with no overwriting permitted. | ||
44 | |||
45 | The implementation provides arbitrary length and numbers | ||
46 | of cells and line/column indexed read access to the scroll | ||
47 | at constant costs. | ||
48 | |||
49 | FIXME: some complain about the history buffer comsuming the | ||
50 | memory of their machines. This problem is critical | ||
51 | since the history does not behave gracefully in cases | ||
52 | where the memory is used up completely. | ||
53 | |||
54 | I put in a workaround that should handle it problem | ||
55 | now gracefully. I'm not satisfied with the solution. | ||
56 | |||
57 | FIXME: Terminating the history is not properly indicated | ||
58 | in the menu. We should throw a signal. | ||
59 | |||
60 | FIXME: There is noticable decrease in speed, also. Perhaps, | ||
61 | there whole feature needs to be revisited therefore. | ||
62 | Disadvantage of a more elaborated, say block-oriented | ||
63 | scheme with wrap around would be it's complexity. | ||
64 | */ | ||
65 | |||
66 | //FIXME: tempory replacement for tmpfile | ||
67 | // this is here one for debugging purpose. | ||
68 | |||
69 | //#define tmpfile xTmpFile | ||
70 | |||
71 | FILE* xTmpFile() | ||
72 | { | ||
73 | static int fid = 0; | ||
74 | char fname[80]; | ||
75 | sprintf(fname,"TmpFile.%d",fid++); | ||
76 | return fopen(fname,"w"); | ||
77 | } | ||
78 | |||
79 | |||
80 | // History Buffer /////////////////////////////////////////// | ||
81 | |||
82 | /* | ||
83 | A Row(X) data type which allows adding elements to the end. | ||
84 | */ | ||
85 | |||
86 | HistoryBuffer::HistoryBuffer() | ||
87 | { | ||
88 | ion = -1; | ||
89 | length = 0; | ||
90 | } | ||
91 | |||
92 | HistoryBuffer::~HistoryBuffer() | ||
93 | { | ||
94 | setScroll(FALSE); | ||
95 | } | ||
96 | |||
97 | void HistoryBuffer::setScroll(bool on) | ||
98 | { | ||
99 | if (on == hasScroll()) return; | ||
100 | |||
101 | if (on) | ||
102 | { | ||
103 | assert( ion < 0 ); | ||
104 | assert( length == 0); | ||
105 | FILE* tmp = tmpfile(); if (!tmp) { perror("konsole: cannot open temp file.\n"); return; } | ||
106 | ion = dup(fileno(tmp)); if (ion<0) perror("konsole: cannot dup temp file.\n"); | ||
107 | fclose(tmp); | ||
108 | } | ||
109 | else | ||
110 | { | ||
111 | assert( ion >= 0 ); | ||
112 | close(ion); | ||
113 | ion = -1; | ||
114 | length = 0; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | bool HistoryBuffer::hasScroll() | ||
119 | { | ||
120 | return ion >= 0; | ||
121 | } | ||
122 | |||
123 | void HistoryBuffer::add(const unsigned char* bytes, int len) | ||
124 | { int rc; | ||
125 | assert(hasScroll()); | ||
126 | rc = lseek(ion,length,SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setScroll(FALSE); return; } | ||
127 | rc = write(ion,bytes,len); if (rc < 0) { perror("HistoryBuffer::add.write"); setScroll(FALSE); return; } | ||
128 | length += rc; | ||
129 | } | ||
130 | |||
131 | void HistoryBuffer::get(unsigned char* bytes, int len, int loc) | ||
132 | { int rc; | ||
133 | assert(hasScroll()); | ||
134 | if (loc < 0 || len < 0 || loc + len > length) | ||
135 | fprintf(stderr,"getHist(...,%d,%d): invalid args.\n",len,loc); | ||
136 | rc = lseek(ion,loc,SEEK_SET); if (rc < 0) { perror("HistoryBuffer::get.seek"); setScroll(FALSE); return; } | ||
137 | rc = read(ion,bytes,len); if (rc < 0) { perror("HistoryBuffer::get.read"); setScroll(FALSE); return; } | ||
138 | } | ||
139 | |||
140 | int HistoryBuffer::len() | ||
141 | { | ||
142 | return length; | ||
143 | } | ||
144 | |||
145 | // History Scroll ////////////////////////////////////// | ||
146 | |||
147 | /* | ||
148 | The history scroll makes a Row(Row(Cell)) from | ||
149 | two history buffers. The index buffer contains | ||
150 | start of line positions which refere to the cells | ||
151 | buffer. | ||
152 | |||
153 | Note that index[0] addresses the second line | ||
154 | (line #1), while the first line (line #0) starts | ||
155 | at 0 in cells. | ||
156 | */ | ||
157 | |||
158 | HistoryScroll::HistoryScroll() | ||
159 | { | ||
160 | } | ||
161 | |||
162 | HistoryScroll::~HistoryScroll() | ||
163 | { | ||
164 | } | ||
165 | |||
166 | void HistoryScroll::setScroll(bool on) | ||
167 | { | ||
168 | index.setScroll(on); | ||
169 | cells.setScroll(on); | ||
170 | } | ||
171 | |||
172 | bool HistoryScroll::hasScroll() | ||
173 | { | ||
174 | return index.hasScroll() && cells.hasScroll(); | ||
175 | } | ||
176 | |||
177 | int HistoryScroll::getLines() | ||
178 | { | ||
179 | if (!hasScroll()) return 0; | ||
180 | return index.len() / sizeof(int); | ||
181 | } | ||
182 | |||
183 | int HistoryScroll::getLineLen(int lineno) | ||
184 | { | ||
185 | if (!hasScroll()) return 0; | ||
186 | return (startOfLine(lineno+1) - startOfLine(lineno)) / sizeof(Character); | ||
187 | } | ||
188 | |||
189 | int HistoryScroll::startOfLine(int lineno) | ||
190 | { | ||
191 | if (lineno <= 0) return 0; | ||
192 | if (!hasScroll()) return 0; | ||
193 | if (lineno <= getLines()) | ||
194 | { int res; | ||
195 | index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int)); | ||
196 | return res; | ||
197 | } | ||
198 | return cells.len(); | ||
199 | } | ||
200 | |||
201 | void HistoryScroll::getCells(int lineno, int colno, int count, Character res[]) | ||
202 | { | ||
203 | assert(hasScroll()); | ||
204 | cells.get((unsigned char*)res,count*sizeof(Character),startOfLine(lineno)+colno*sizeof(Character)); | ||
205 | } | ||
206 | |||
207 | void HistoryScroll::addCells(Character text[], int count) | ||
208 | { | ||
209 | if (!hasScroll()) return; | ||
210 | cells.add((unsigned char*)text,count*sizeof(Character)); | ||
211 | } | ||
212 | |||
213 | void HistoryScroll::addLine() | ||
214 | { | ||
215 | if (!hasScroll()) return; | ||
216 | int locn = cells.len(); | ||
217 | index.add((unsigned char*)&locn,sizeof(int)); | ||
218 | } | ||
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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [history.h] History Buffer */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* */ | ||
14 | /* Ported Konsole to Qt/Embedded */ | ||
15 | /* */ | ||
16 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
17 | /* */ | ||
18 | /* -------------------------------------------------------------------------- */ | ||
19 | /* */ | ||
20 | /* ported embedded_konsole to opie-console */ | ||
21 | /* */ | ||
22 | /* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ | ||
23 | /* */ | ||
24 | /* -------------------------------------------------------------------------- */ | ||
25 | |||
26 | #ifndef HISTORY_H | ||
27 | #define HISTORY_H | ||
28 | |||
29 | #include "common.h" | ||
30 | |||
31 | /* | ||
32 | An extendable tmpfile(1) based buffer. | ||
33 | */ | ||
34 | class HistoryBuffer | ||
35 | { | ||
36 | public: | ||
37 | HistoryBuffer(); | ||
38 | ~HistoryBuffer(); | ||
39 | |||
40 | public: | ||
41 | void setScroll(bool on); | ||
42 | bool hasScroll(); | ||
43 | |||
44 | public: | ||
45 | void add(const unsigned char* bytes, int len); | ||
46 | void get(unsigned char* bytes, int len, int loc); | ||
47 | int len(); | ||
48 | |||
49 | private: | ||
50 | int ion; | ||
51 | int length; | ||
52 | }; | ||
53 | |||
54 | class HistoryScroll | ||
55 | { | ||
56 | public: | ||
57 | HistoryScroll(); | ||
58 | ~HistoryScroll(); | ||
59 | |||
60 | public: | ||
61 | void setScroll(bool on); | ||
62 | bool hasScroll(); | ||
63 | |||
64 | public: // access to history | ||
65 | int getLines(); | ||
66 | int getLineLen(int lineno); | ||
67 | void getCells(int lineno, int colno, int count, Character res[]); | ||
68 | |||
69 | public: // backward compatibility (obsolete) | ||
70 | Character getCell(int lineno, int colno) { Character res; getCells(lineno,colno,1,&res); return res; } | ||
71 | |||
72 | public: // adding lines. | ||
73 | void addCells(Character a[], int count); | ||
74 | void addLine(); | ||
75 | |||
76 | private: | ||
77 | int startOfLine(int lineno); | ||
78 | HistoryBuffer index; // lines Row(int) | ||
79 | HistoryBuffer cells; // text Row(Character) | ||
80 | }; | ||
81 | |||
82 | #endif // HISTORY_H | ||
diff --git a/noncore/apps/opie-console/history.o b/noncore/apps/opie-console/history.o new file mode 100644 index 0000000..256d3a5 --- a/dev/null +++ b/noncore/apps/opie-console/history.o | |||
Binary files differ | |||
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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [keytrans.C] Keyboard Translation */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /* | ||
20 | The keyboard translation table allows to configure konsoles behavior | ||
21 | on key strokes. | ||
22 | |||
23 | FIXME: some bug crept in, disallowing '\0' to be emitted. | ||
24 | */ | ||
25 | |||
26 | #include "keytrans.h" | ||
27 | |||
28 | #include <qpe/qpeapplication.h> | ||
29 | |||
30 | #include <qnamespace.h> | ||
31 | #include <qbuffer.h> | ||
32 | #include <qobject.h> | ||
33 | #include <qdict.h> | ||
34 | #include <qintdict.h> | ||
35 | #include <qfile.h> | ||
36 | #include <qglobal.h> | ||
37 | #include <qdir.h> | ||
38 | |||
39 | //#include <kstddirs.h> | ||
40 | //nclude <klocale.h> | ||
41 | |||
42 | #include <stdio.h> | ||
43 | |||
44 | |||
45 | #undef USE_APPDATA_DIR | ||
46 | |||
47 | |||
48 | #define HERE printf("%s(%d): here\n",__FILE__,__LINE__) | ||
49 | |||
50 | /* KeyEntry | ||
51 | |||
52 | instances represent the individual assignments | ||
53 | */ | ||
54 | |||
55 | KeyTrans::KeyEntry::KeyEntry(int _ref, int _key, int _bits, int _mask, int _cmd, QString _txt) | ||
56 | : ref(_ref), key(_key), bits(_bits), mask(_mask), cmd(_cmd), txt(_txt) | ||
57 | { | ||
58 | } | ||
59 | |||
60 | KeyTrans::KeyEntry::~KeyEntry() | ||
61 | { | ||
62 | } | ||
63 | |||
64 | bool KeyTrans::KeyEntry::matches(int _key, int _bits, int _mask) | ||
65 | { int m = mask & _mask; | ||
66 | return _key == key && (bits & m) == (_bits & m); | ||
67 | } | ||
68 | |||
69 | QString KeyTrans::KeyEntry::text() | ||
70 | { | ||
71 | return txt; | ||
72 | } | ||
73 | |||
74 | /* KeyTrans | ||
75 | |||
76 | combines the individual assignments to a proper map | ||
77 | Takes part in a collection themself. | ||
78 | */ | ||
79 | |||
80 | KeyTrans::KeyTrans() | ||
81 | { | ||
82 | path = ""; | ||
83 | numb = 0; | ||
84 | } | ||
85 | |||
86 | KeyTrans::~KeyTrans() | ||
87 | { | ||
88 | } | ||
89 | |||
90 | KeyTrans::KeyEntry* KeyTrans::addEntry(int ref, int key, int bits, int mask, int cmd, QString txt) | ||
91 | // returns conflicting entry | ||
92 | { | ||
93 | for (QListIterator<KeyEntry> it(table); it.current(); ++it) | ||
94 | { | ||
95 | if (it.current()->matches(key,bits,mask)) | ||
96 | { | ||
97 | return it.current(); | ||
98 | } | ||
99 | } | ||
100 | table.append(new KeyEntry(ref,key,bits,mask,cmd,txt)); | ||
101 | return (KeyEntry*)NULL; | ||
102 | } | ||
103 | |||
104 | bool KeyTrans::findEntry(int key, int bits, int* cmd, const char** txt, int* len) | ||
105 | { | ||
106 | for (QListIterator<KeyEntry> it(table); it.current(); ++it) | ||
107 | if (it.current()->matches(key,bits,0xffff)) | ||
108 | { | ||
109 | *cmd = it.current()->cmd; | ||
110 | *txt = it.current()->txt.ascii(); | ||
111 | *len = it.current()->txt.length(); | ||
112 | return TRUE; | ||
113 | } | ||
114 | return FALSE; | ||
115 | } | ||
116 | |||
117 | /* ------------------------------------------------------------------------- */ | ||
118 | /* */ | ||
119 | /* Scanner for keyboard configuration */ | ||
120 | /* */ | ||
121 | /* ------------------------------------------------------------------------- */ | ||
122 | |||
123 | // regular tokenizer | ||
124 | /* Tokens | ||
125 | - Spaces | ||
126 | - Name (A-Za-z0-9)+ | ||
127 | - String | ||
128 | - Opr on of +-: | ||
129 | */ | ||
130 | |||
131 | #define SYMName 0 | ||
132 | #define SYMString 1 | ||
133 | #define SYMEol 2 | ||
134 | #define SYMEof 3 | ||
135 | #define SYMOpr 4 | ||
136 | #define SYMError 5 | ||
137 | |||
138 | #define inRange(L,X,H) ((L <= X) && (X <= H)) | ||
139 | #define isNibble(X) (inRange('A',X,'F')||inRange('a',X,'f')||inRange('0',X,'9')) | ||
140 | #define convNibble(X) (inRange('0',X,'9')?X-'0':X+10-(inRange('A',X,'F')?'A':'a')) | ||
141 | |||
142 | class KeytabReader | ||
143 | { | ||
144 | public: | ||
145 | KeytabReader(QString p, QIODevice &d); | ||
146 | public: | ||
147 | void getCc(); | ||
148 | void getSymbol(); | ||
149 | void parseTo(KeyTrans* kt); | ||
150 | void ReportError(const char* msg); | ||
151 | void ReportToken(); // diagnostic | ||
152 | private: | ||
153 | int sym; | ||
154 | QString res; | ||
155 | int len; | ||
156 | int slinno; | ||
157 | int scolno; | ||
158 | private: | ||
159 | int cc; | ||
160 | int linno; | ||
161 | int colno; | ||
162 | QIODevice* buf; | ||
163 | QString path; | ||
164 | }; | ||
165 | |||
166 | |||
167 | KeytabReader::KeytabReader(QString p, QIODevice &d) | ||
168 | { | ||
169 | path = p; | ||
170 | buf = &d; | ||
171 | cc = 0; | ||
172 | } | ||
173 | |||
174 | void KeytabReader::getCc() | ||
175 | { | ||
176 | if (cc == '\n') { linno += 1; colno = 0; } | ||
177 | if (cc < 0) return; | ||
178 | cc = buf->getch(); | ||
179 | colno += 1; | ||
180 | } | ||
181 | |||
182 | void KeytabReader::getSymbol() | ||
183 | { | ||
184 | res = ""; len = 0; sym = SYMError; | ||
185 | while (cc == ' ') getCc(); // skip spaces | ||
186 | if (cc == '#') // skip comment | ||
187 | { | ||
188 | while (cc != '\n' && cc > 0) getCc(); | ||
189 | } | ||
190 | slinno = linno; | ||
191 | scolno = colno; | ||
192 | if (cc <= 0) | ||
193 | { | ||
194 | sym = SYMEof; return; // eos | ||
195 | } | ||
196 | if (cc == '\n') | ||
197 | { | ||
198 | getCc(); | ||
199 | sym = SYMEol; return; // eol | ||
200 | } | ||
201 | if (inRange('A',cc,'Z')||inRange('a',cc,'z')||inRange('0',cc,'9')) | ||
202 | { | ||
203 | while (inRange('A',cc,'Z') || inRange('a',cc,'z') || inRange('0',cc,'9')) | ||
204 | { | ||
205 | res = res + (char)cc; | ||
206 | getCc(); | ||
207 | } | ||
208 | sym = SYMName; | ||
209 | return; | ||
210 | } | ||
211 | if (strchr("+-:",cc)) | ||
212 | { | ||
213 | res = ""; | ||
214 | res = res + (char)cc; | ||
215 | getCc(); | ||
216 | sym = SYMOpr; return; | ||
217 | } | ||
218 | if (cc == '"') | ||
219 | { | ||
220 | getCc(); | ||
221 | while (cc >= ' ' && cc != '"') | ||
222 | { int sc; | ||
223 | if (cc == '\\') // handle quotation | ||
224 | { | ||
225 | getCc(); | ||
226 | switch (cc) | ||
227 | { | ||
228 | case 'E' : sc = 27; getCc(); break; | ||
229 | case 'b' : sc = 8; getCc(); break; | ||
230 | case 'f' : sc = 12; getCc(); break; | ||
231 | case 't' : sc = 9; getCc(); break; | ||
232 | case 'r' : sc = 13; getCc(); break; | ||
233 | case 'n' : sc = 10; getCc(); break; | ||
234 | case '\\' : // fall thru | ||
235 | case '"' : sc = cc; getCc(); break; | ||
236 | case 'x' : getCc(); | ||
237 | sc = 0; | ||
238 | if (!isNibble(cc)) return; sc = 16*sc + convNibble(cc); getCc(); | ||
239 | if (!isNibble(cc)) return; sc = 16*sc + convNibble(cc); getCc(); | ||
240 | break; | ||
241 | default : return; | ||
242 | } | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | // regular char | ||
247 | sc = cc; getCc(); | ||
248 | } | ||
249 | res = res + (char)sc; | ||
250 | len = len + 1; | ||
251 | } | ||
252 | if (cc != '"') return; | ||
253 | getCc(); | ||
254 | sym = SYMString; return; | ||
255 | } | ||
256 | } | ||
257 | |||
258 | void KeytabReader::ReportToken() // diagnostic | ||
259 | { | ||
260 | printf("sym(%d): ",slinno); | ||
261 | switch(sym) | ||
262 | { | ||
263 | case SYMEol : printf("End of line"); break; | ||
264 | case SYMEof : printf("End of file"); break; | ||
265 | case SYMName : printf("Name: %s",res.latin1()); break; | ||
266 | case SYMOpr : printf("Opr : %s",res.latin1()); break; | ||
267 | case SYMString : printf("String len %d,%d ",res.length(),len); | ||
268 | for (unsigned i = 0; i < res.length(); i++) | ||
269 | printf(" %02x(%c)",res.latin1()[i],res.latin1()[i]>=' '?res.latin1()[i]:'?'); | ||
270 | break; | ||
271 | } | ||
272 | printf("\n"); | ||
273 | } | ||
274 | |||
275 | void KeytabReader::ReportError(const char* msg) // diagnostic | ||
276 | { | ||
277 | fprintf(stderr,"%s(%d,%d):error: %s.\n",path.ascii(),slinno,scolno,msg); | ||
278 | } | ||
279 | |||
280 | // local symbol tables --------------------------------------------------------------------- | ||
281 | |||
282 | class KeyTransSymbols | ||
283 | { | ||
284 | public: | ||
285 | KeyTransSymbols(); | ||
286 | protected: | ||
287 | void defOprSyms(); | ||
288 | void defModSyms(); | ||
289 | void defKeySyms(); | ||
290 | void defKeySym(const char* key, int val); | ||
291 | void defOprSym(const char* key, int val); | ||
292 | void defModSym(const char* key, int val); | ||
293 | public: | ||
294 | QDict<QObject> keysyms; | ||
295 | QDict<QObject> modsyms; | ||
296 | QDict<QObject> oprsyms; | ||
297 | }; | ||
298 | |||
299 | static KeyTransSymbols * syms = 0L; | ||
300 | |||
301 | // parser ---------------------------------------------------------------------------------- | ||
302 | /* Syntax | ||
303 | - Line :: [KeyName { ("+" | "-") ModeName } ":" (String|CommandName)] "\n" | ||
304 | - Comment :: '#' (any but \n)* | ||
305 | */ | ||
306 | |||
307 | KeyTrans* KeyTrans::fromDevice(QString path, QIODevice &buf) | ||
308 | { | ||
309 | KeyTrans* kt = new KeyTrans; | ||
310 | kt->path = path; | ||
311 | KeytabReader ktr(path,buf); ktr.parseTo(kt); | ||
312 | return kt; | ||
313 | } | ||
314 | |||
315 | |||
316 | #define assertSyntax(Cond,Message) if (!(Cond)) { ReportError(Message); goto ERROR; } | ||
317 | |||
318 | void KeytabReader::parseTo(KeyTrans* kt) | ||
319 | { | ||
320 | // Opening sequence | ||
321 | |||
322 | buf->open(IO_ReadOnly); | ||
323 | getCc(); | ||
324 | linno = 1; | ||
325 | colno = 1; | ||
326 | getSymbol(); | ||
327 | |||
328 | Loop: | ||
329 | // syntax: ["key" KeyName { ("+" | "-") ModeName } ":" String/CommandName] ["#" Comment] | ||
330 | if (sym == SYMName && !strcmp(res.latin1(),"keyboard")) | ||
331 | { | ||
332 | getSymbol(); assertSyntax(sym == SYMString, "Header expected") | ||
333 | kt->hdr = res.latin1(); | ||
334 | getSymbol(); assertSyntax(sym == SYMEol, "Text unexpected") | ||
335 | getSymbol(); // eoln | ||
336 | goto Loop; | ||
337 | } | ||
338 | if (sym == SYMName && !strcmp(res.latin1(),"key")) | ||
339 | { | ||
340 | //printf("line %3d: ",startofsym); | ||
341 | getSymbol(); assertSyntax(sym == SYMName, "Name expected") | ||
342 | assertSyntax(syms->keysyms[res], "Unknown key name") | ||
343 | int key = (int)syms->keysyms[res]-1; | ||
344 | //printf(" key %s (%04x)",res.latin1(),(int)syms->keysyms[res]-1); | ||
345 | getSymbol(); // + - : | ||
346 | int mode = 0; | ||
347 | int mask = 0; | ||
348 | while (sym == SYMOpr && (!strcmp(res.latin1(),"+") || !strcmp(res.latin1(),"-"))) | ||
349 | { | ||
350 | bool on = !strcmp(res.latin1(),"+"); | ||
351 | getSymbol(); | ||
352 | // mode name | ||
353 | assertSyntax(sym == SYMName, "Name expected") | ||
354 | assertSyntax(syms->modsyms[res], "Unknown mode name") | ||
355 | int bits = (int)syms->modsyms[res]-1; | ||
356 | if (mask & (1 << bits)) | ||
357 | { | ||
358 | fprintf(stderr,"%s(%d,%d): mode name used multible times.\n",path.ascii(),slinno,scolno); | ||
359 | } | ||
360 | else | ||
361 | { | ||
362 | mode |= (on << bits); | ||
363 | mask |= (1 << bits); | ||
364 | } | ||
365 | //printf(", mode %s(%d) %s",res.latin1(),(int)syms->modsyms[res]-1,on?"on":"off"); | ||
366 | getSymbol(); | ||
367 | } | ||
368 | assertSyntax(sym == SYMOpr && !strcmp(res.latin1(),":"), "':' expected") | ||
369 | getSymbol(); | ||
370 | // string or command | ||
371 | assertSyntax(sym == SYMName || sym == SYMString,"Command or string expected") | ||
372 | int cmd = 0; | ||
373 | if (sym == SYMName) | ||
374 | { | ||
375 | assertSyntax(syms->oprsyms[res], "Unknown operator name") | ||
376 | cmd = (int)syms->oprsyms[res]-1; | ||
377 | //printf(": do %s(%d)",res.latin1(),(int)syms->oprsyms[res]-1); | ||
378 | } | ||
379 | if (sym == SYMString) | ||
380 | { | ||
381 | cmd = CMD_send; | ||
382 | //printf(": send"); | ||
383 | //for (unsigned i = 0; i < res.length(); i++) | ||
384 | //printf(" %02x(%c)",res.latin1()[i],res.latin1()[i]>=' '?res.latin1()[i]:'?'); | ||
385 | } | ||
386 | //printf(". summary %04x,%02x,%02x,%d\n",key,mode,mask,cmd); | ||
387 | KeyTrans::KeyEntry* ke = kt->addEntry(slinno,key,mode,mask,cmd,res); | ||
388 | if (ke) | ||
389 | { | ||
390 | fprintf(stderr,"%s(%d): keystroke already assigned in line %d.\n",path.ascii(),slinno,ke->ref); | ||
391 | } | ||
392 | getSymbol(); | ||
393 | assertSyntax(sym == SYMEol, "Unexpected text") | ||
394 | goto Loop; | ||
395 | } | ||
396 | if (sym == SYMEol) | ||
397 | { | ||
398 | getSymbol(); | ||
399 | goto Loop; | ||
400 | } | ||
401 | |||
402 | assertSyntax(sym == SYMEof, "Undecodable Line") | ||
403 | |||
404 | buf->close(); | ||
405 | return; | ||
406 | |||
407 | ERROR: | ||
408 | while (sym != SYMEol && sym != SYMEof) getSymbol(); // eoln | ||
409 | goto Loop; | ||
410 | } | ||
411 | |||
412 | |||
413 | KeyTrans* KeyTrans::defaultKeyTrans() | ||
414 | { | ||
415 | QCString txt = | ||
416 | #include "default.keytab.h" | ||
417 | ; | ||
418 | QBuffer buf(txt); | ||
419 | return fromDevice("[buildin]",buf); | ||
420 | } | ||
421 | |||
422 | KeyTrans* KeyTrans::fromFile(const char* path) | ||
423 | { | ||
424 | QFile file(path); | ||
425 | return fromDevice(path,file); | ||
426 | } | ||
427 | |||
428 | // local symbol tables --------------------------------------------------------------------- | ||
429 | // material needed for parsing the config file. | ||
430 | // This is incomplete work. | ||
431 | |||
432 | void KeyTransSymbols::defKeySym(const char* key, int val) | ||
433 | { | ||
434 | keysyms.insert(key,(QObject*)(val+1)); | ||
435 | } | ||
436 | |||
437 | void KeyTransSymbols::defOprSym(const char* key, int val) | ||
438 | { | ||
439 | oprsyms.insert(key,(QObject*)(val+1)); | ||
440 | } | ||
441 | |||
442 | void KeyTransSymbols::defModSym(const char* key, int val) | ||
443 | { | ||
444 | modsyms.insert(key,(QObject*)(val+1)); | ||
445 | } | ||
446 | |||
447 | void KeyTransSymbols::defOprSyms() | ||
448 | { | ||
449 | // Modifier | ||
450 | defOprSym("scrollLineUp", CMD_scrollLineUp ); | ||
451 | defOprSym("scrollLineDown",CMD_scrollLineDown); | ||
452 | defOprSym("scrollPageUp", CMD_scrollPageUp ); | ||
453 | defOprSym("scrollPageDown",CMD_scrollPageDown); | ||
454 | defOprSym("emitSelection", CMD_emitSelection ); | ||
455 | defOprSym("prevSession", CMD_prevSession ); | ||
456 | defOprSym("nextSession", CMD_nextSession ); | ||
457 | } | ||
458 | |||
459 | void KeyTransSymbols::defModSyms() | ||
460 | { | ||
461 | // Modifier | ||
462 | defModSym("Shift", BITS_Shift ); | ||
463 | defModSym("Control", BITS_Control ); | ||
464 | defModSym("Alt", BITS_Alt ); | ||
465 | // Modes | ||
466 | defModSym("BsHack", BITS_BsHack ); // deprecated | ||
467 | defModSym("Ansi", BITS_Ansi ); | ||
468 | defModSym("NewLine", BITS_NewLine ); | ||
469 | defModSym("AppCuKeys", BITS_AppCuKeys ); | ||
470 | } | ||
471 | |||
472 | void KeyTransSymbols::defKeySyms() | ||
473 | { | ||
474 | // Grey keys | ||
475 | defKeySym("Escape", Qt::Key_Escape ); | ||
476 | defKeySym("Tab", Qt::Key_Tab ); | ||
477 | defKeySym("Backtab", Qt::Key_Backtab ); | ||
478 | defKeySym("Backspace", Qt::Key_Backspace ); | ||
479 | defKeySym("Return", Qt::Key_Return ); | ||
480 | defKeySym("Enter", Qt::Key_Enter ); | ||
481 | defKeySym("Insert", Qt::Key_Insert ); | ||
482 | defKeySym("Delete", Qt::Key_Delete ); | ||
483 | defKeySym("Pause", Qt::Key_Pause ); | ||
484 | defKeySym("Print", Qt::Key_Print ); | ||
485 | defKeySym("SysReq", Qt::Key_SysReq ); | ||
486 | defKeySym("Home", Qt::Key_Home ); | ||
487 | defKeySym("End", Qt::Key_End ); | ||
488 | defKeySym("Left", Qt::Key_Left ); | ||
489 | defKeySym("Up", Qt::Key_Up ); | ||
490 | defKeySym("Right", Qt::Key_Right ); | ||
491 | defKeySym("Down", Qt::Key_Down ); | ||
492 | defKeySym("Prior", Qt::Key_Prior ); | ||
493 | defKeySym("Next", Qt::Key_Next ); | ||
494 | defKeySym("Shift", Qt::Key_Shift ); | ||
495 | defKeySym("Control", Qt::Key_Control ); | ||
496 | defKeySym("Meta", Qt::Key_Meta ); | ||
497 | defKeySym("Alt", Qt::Key_Alt ); | ||
498 | defKeySym("CapsLock", Qt::Key_CapsLock ); | ||
499 | defKeySym("NumLock", Qt::Key_NumLock ); | ||
500 | defKeySym("ScrollLock", Qt::Key_ScrollLock ); | ||
501 | defKeySym("F1", Qt::Key_F1 ); | ||
502 | defKeySym("F2", Qt::Key_F2 ); | ||
503 | defKeySym("F3", Qt::Key_F3 ); | ||
504 | defKeySym("F4", Qt::Key_F4 ); | ||
505 | defKeySym("F5", Qt::Key_F5 ); | ||
506 | defKeySym("F6", Qt::Key_F6 ); | ||
507 | defKeySym("F7", Qt::Key_F7 ); | ||
508 | defKeySym("F8", Qt::Key_F8 ); | ||
509 | defKeySym("F9", Qt::Key_F9 ); | ||
510 | defKeySym("F10", Qt::Key_F10 ); | ||
511 | defKeySym("F11", Qt::Key_F11 ); | ||
512 | defKeySym("F12", Qt::Key_F12 ); | ||
513 | defKeySym("F13", Qt::Key_F13 ); | ||
514 | defKeySym("F14", Qt::Key_F14 ); | ||
515 | defKeySym("F15", Qt::Key_F15 ); | ||
516 | defKeySym("F16", Qt::Key_F16 ); | ||
517 | defKeySym("F17", Qt::Key_F17 ); | ||
518 | defKeySym("F18", Qt::Key_F18 ); | ||
519 | defKeySym("F19", Qt::Key_F19 ); | ||
520 | defKeySym("F20", Qt::Key_F20 ); | ||
521 | defKeySym("F21", Qt::Key_F21 ); | ||
522 | defKeySym("F22", Qt::Key_F22 ); | ||
523 | defKeySym("F23", Qt::Key_F23 ); | ||
524 | defKeySym("F24", Qt::Key_F24 ); | ||
525 | defKeySym("F25", Qt::Key_F25 ); | ||
526 | defKeySym("F26", Qt::Key_F26 ); | ||
527 | defKeySym("F27", Qt::Key_F27 ); | ||
528 | defKeySym("F28", Qt::Key_F28 ); | ||
529 | defKeySym("F29", Qt::Key_F29 ); | ||
530 | defKeySym("F30", Qt::Key_F30 ); | ||
531 | defKeySym("F31", Qt::Key_F31 ); | ||
532 | defKeySym("F32", Qt::Key_F32 ); | ||
533 | defKeySym("F33", Qt::Key_F33 ); | ||
534 | defKeySym("F34", Qt::Key_F34 ); | ||
535 | defKeySym("F35", Qt::Key_F35 ); | ||
536 | defKeySym("Super_L", Qt::Key_Super_L ); | ||
537 | defKeySym("Super_R", Qt::Key_Super_R ); | ||
538 | defKeySym("Menu", Qt::Key_Menu ); | ||
539 | defKeySym("Hyper_L", Qt::Key_Hyper_L ); | ||
540 | defKeySym("Hyper_R", Qt::Key_Hyper_R ); | ||
541 | |||
542 | // Regular keys | ||
543 | defKeySym("Space", Qt::Key_Space ); | ||
544 | defKeySym("Exclam", Qt::Key_Exclam ); | ||
545 | defKeySym("QuoteDbl", Qt::Key_QuoteDbl ); | ||
546 | defKeySym("NumberSign", Qt::Key_NumberSign ); | ||
547 | defKeySym("Dollar", Qt::Key_Dollar ); | ||
548 | defKeySym("Percent", Qt::Key_Percent ); | ||
549 | defKeySym("Ampersand", Qt::Key_Ampersand ); | ||
550 | defKeySym("Apostrophe", Qt::Key_Apostrophe ); | ||
551 | defKeySym("ParenLeft", Qt::Key_ParenLeft ); | ||
552 | defKeySym("ParenRight", Qt::Key_ParenRight ); | ||
553 | defKeySym("Asterisk", Qt::Key_Asterisk ); | ||
554 | defKeySym("Plus", Qt::Key_Plus ); | ||
555 | defKeySym("Comma", Qt::Key_Comma ); | ||
556 | defKeySym("Minus", Qt::Key_Minus ); | ||
557 | defKeySym("Period", Qt::Key_Period ); | ||
558 | defKeySym("Slash", Qt::Key_Slash ); | ||
559 | defKeySym("0", Qt::Key_0 ); | ||
560 | defKeySym("1", Qt::Key_1 ); | ||
561 | defKeySym("2", Qt::Key_2 ); | ||
562 | defKeySym("3", Qt::Key_3 ); | ||
563 | defKeySym("4", Qt::Key_4 ); | ||
564 | defKeySym("5", Qt::Key_5 ); | ||
565 | defKeySym("6", Qt::Key_6 ); | ||
566 | defKeySym("7", Qt::Key_7 ); | ||
567 | defKeySym("8", Qt::Key_8 ); | ||
568 | defKeySym("9", Qt::Key_9 ); | ||
569 | defKeySym("Colon", Qt::Key_Colon ); | ||
570 | defKeySym("Semicolon", Qt::Key_Semicolon ); | ||
571 | defKeySym("Less", Qt::Key_Less ); | ||
572 | defKeySym("Equal", Qt::Key_Equal ); | ||
573 | defKeySym("Greater", Qt::Key_Greater ); | ||
574 | defKeySym("Question", Qt::Key_Question ); | ||
575 | defKeySym("At", Qt::Key_At ); | ||
576 | defKeySym("A", Qt::Key_A ); | ||
577 | defKeySym("B", Qt::Key_B ); | ||
578 | defKeySym("C", Qt::Key_C ); | ||
579 | defKeySym("D", Qt::Key_D ); | ||
580 | defKeySym("E", Qt::Key_E ); | ||
581 | defKeySym("F", Qt::Key_F ); | ||
582 | defKeySym("G", Qt::Key_G ); | ||
583 | defKeySym("H", Qt::Key_H ); | ||
584 | defKeySym("I", Qt::Key_I ); | ||
585 | defKeySym("J", Qt::Key_J ); | ||
586 | defKeySym("K", Qt::Key_K ); | ||
587 | defKeySym("L", Qt::Key_L ); | ||
588 | defKeySym("M", Qt::Key_M ); | ||
589 | defKeySym("N", Qt::Key_N ); | ||
590 | defKeySym("O", Qt::Key_O ); | ||
591 | defKeySym("P", Qt::Key_P ); | ||
592 | defKeySym("Q", Qt::Key_Q ); | ||
593 | defKeySym("R", Qt::Key_R ); | ||
594 | defKeySym("S", Qt::Key_S ); | ||
595 | defKeySym("T", Qt::Key_T ); | ||
596 | defKeySym("U", Qt::Key_U ); | ||
597 | defKeySym("V", Qt::Key_V ); | ||
598 | defKeySym("W", Qt::Key_W ); | ||
599 | defKeySym("X", Qt::Key_X ); | ||
600 | defKeySym("Y", Qt::Key_Y ); | ||
601 | defKeySym("Z", Qt::Key_Z ); | ||
602 | defKeySym("BracketLeft", Qt::Key_BracketLeft ); | ||
603 | defKeySym("Backslash", Qt::Key_Backslash ); | ||
604 | defKeySym("BracketRight", Qt::Key_BracketRight); | ||
605 | defKeySym("AsciiCircum", Qt::Key_AsciiCircum ); | ||
606 | defKeySym("Underscore", Qt::Key_Underscore ); | ||
607 | defKeySym("QuoteLeft", Qt::Key_QuoteLeft ); | ||
608 | defKeySym("BraceLeft", Qt::Key_BraceLeft ); | ||
609 | defKeySym("Bar", Qt::Key_Bar ); | ||
610 | defKeySym("BraceRight", Qt::Key_BraceRight ); | ||
611 | defKeySym("AsciiTilde", Qt::Key_AsciiTilde ); | ||
612 | } | ||
613 | |||
614 | KeyTransSymbols::KeyTransSymbols() | ||
615 | { | ||
616 | defModSyms(); | ||
617 | defOprSyms(); | ||
618 | defKeySyms(); | ||
619 | } | ||
620 | |||
621 | // Global material ----------------------------------------------------------- | ||
622 | |||
623 | static int keytab_serial = 0; //FIXME: remove,localize | ||
624 | |||
625 | static QIntDict<KeyTrans> * numb2keymap = 0L; | ||
626 | static QDict<KeyTrans> * path2keymap = 0L; | ||
627 | |||
628 | KeyTrans* KeyTrans::find(int numb) | ||
629 | { | ||
630 | KeyTrans* res = numb2keymap->find(numb); | ||
631 | return res ? res : numb2keymap->find(0); | ||
632 | } | ||
633 | |||
634 | KeyTrans* KeyTrans::find(const char* path) | ||
635 | { | ||
636 | KeyTrans* res = path2keymap->find(path); | ||
637 | return res ? res : numb2keymap->find(0); | ||
638 | } | ||
639 | |||
640 | int KeyTrans::count() | ||
641 | { | ||
642 | return numb2keymap->count(); | ||
643 | } | ||
644 | |||
645 | void KeyTrans::addKeyTrans() | ||
646 | { | ||
647 | this->numb = keytab_serial ++; | ||
648 | numb2keymap->insert(numb,this); | ||
649 | path2keymap->insert(path,this); | ||
650 | } | ||
651 | |||
652 | void KeyTrans::loadAll() | ||
653 | { | ||
654 | if (!numb2keymap) | ||
655 | numb2keymap = new QIntDict<KeyTrans>; | ||
656 | if (!path2keymap) | ||
657 | path2keymap = new QDict<KeyTrans>; | ||
658 | if (!syms) | ||
659 | syms = new KeyTransSymbols; | ||
660 | |||
661 | defaultKeyTrans()->addKeyTrans(); | ||
662 | |||
663 | |||
664 | QString path = QPEApplication::qpeDir() + "etc/keytabs"; | ||
665 | QDir dir(path); | ||
666 | QStringList lst = dir.entryList("*.keytab"); | ||
667 | |||
668 | for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it ) { | ||
669 | QFile file(path + "/" + *it); | ||
670 | KeyTrans* sc = KeyTrans::fromDevice(*it, file); | ||
671 | if (sc) { | ||
672 | sc->addKeyTrans(); | ||
673 | } | ||
674 | } | ||
675 | |||
676 | } | ||
677 | |||
678 | // Debugging material ----------------------------------------------------------- | ||
679 | /* | ||
680 | void TestTokenizer(QBuffer &buf) | ||
681 | { | ||
682 | // opening sequence | ||
683 | |||
684 | buf.open(IO_ReadOnly); | ||
685 | cc = buf.getch(); | ||
686 | lineno = 1; | ||
687 | |||
688 | // Test tokenizer | ||
689 | |||
690 | while (getSymbol(buf)) ReportToken(); | ||
691 | |||
692 | buf.close(); | ||
693 | } | ||
694 | |||
695 | void test() | ||
696 | { | ||
697 | // Opening sequence | ||
698 | |||
699 | QCString txt = | ||
700 | #include "default.keytab.h" | ||
701 | ; | ||
702 | QBuffer buf(txt); | ||
703 | if (0) TestTokenizer(buf); | ||
704 | if (1) { KeyTrans kt; kt.scanTable(buf); } | ||
705 | } | ||
706 | */ | ||
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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [keytrans.h] X Terminal Emulation */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #ifndef KEYTRANS_H | ||
20 | #define KEYTRANS_H | ||
21 | |||
22 | #include <qstring.h> | ||
23 | #include <qlist.h> | ||
24 | #include <qiodevice.h> | ||
25 | |||
26 | #define BITS_NewLine 0 | ||
27 | #define BITS_BsHack 1 | ||
28 | #define BITS_Ansi 2 | ||
29 | #define BITS_AppCuKeys 3 | ||
30 | #define BITS_Control 4 | ||
31 | #define BITS_Shift 5 | ||
32 | #define BITS_Alt 6 | ||
33 | #define BITS_COUNT 7 | ||
34 | |||
35 | #define CMD_send 0 | ||
36 | #define CMD_emitSelection 1 | ||
37 | #define CMD_scrollPageUp 2 | ||
38 | #define CMD_scrollPageDown 3 | ||
39 | #define CMD_scrollLineUp 4 | ||
40 | #define CMD_scrollLineDown 5 | ||
41 | #define CMD_prevSession 6 | ||
42 | #define CMD_nextSession 7 | ||
43 | |||
44 | #define BITS(x,v) ((((v)!=0)<<(x))) | ||
45 | |||
46 | |||
47 | class KeyTrans | ||
48 | { | ||
49 | public: | ||
50 | KeyTrans(); | ||
51 | ~KeyTrans(); | ||
52 | static KeyTrans* defaultKeyTrans(); | ||
53 | static KeyTrans* fromFile(const char* path); | ||
54 | static KeyTrans* find(int numb); | ||
55 | static KeyTrans* find(const char* path); | ||
56 | public: | ||
57 | static int count(); | ||
58 | static void loadAll(); | ||
59 | public: | ||
60 | bool findEntry(int key, int bits, int* cmd, const char** txt, int* len); | ||
61 | private: | ||
62 | void addKeyTrans(); | ||
63 | static KeyTrans* fromDevice(QString path, QIODevice &buf); | ||
64 | public: | ||
65 | class KeyEntry | ||
66 | { | ||
67 | public: | ||
68 | KeyEntry(int ref, int key, int bits, int mask, int cmd, QString txt); | ||
69 | ~KeyEntry(); | ||
70 | public: | ||
71 | bool matches(int key, int bits, int mask); | ||
72 | QString text(); | ||
73 | public: | ||
74 | int ref; | ||
75 | private: | ||
76 | int key; | ||
77 | int bits; | ||
78 | int mask; | ||
79 | public: | ||
80 | int cmd; | ||
81 | QString txt; | ||
82 | }; | ||
83 | public: | ||
84 | KeyEntry* addEntry(int ref, int key, int bits, int mask, int cmd, QString txt); | ||
85 | private: | ||
86 | QList<KeyEntry> table; | ||
87 | public: //FIXME: we'd do better | ||
88 | QString hdr; | ||
89 | int numb; | ||
90 | QString path; | ||
91 | }; | ||
92 | |||
93 | #endif | ||
diff --git a/noncore/apps/opie-console/keytrans.o b/noncore/apps/opie-console/keytrans.o new file mode 100644 index 0000000..2557f8a --- a/dev/null +++ b/noncore/apps/opie-console/keytrans.o | |||
Binary files differ | |||
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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [screen.C] Screen Data Type */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /*! \file | ||
20 | */ | ||
21 | |||
22 | /*! \class Screen | ||
23 | |||
24 | \brief The image manipulated by the emulation. | ||
25 | |||
26 | This class implements the operations of the terminal emulation framework. | ||
27 | It is a complete passive device, driven by the emulation decoder | ||
28 | (TEmuVT102). By this it forms in fact an ADT, that defines operations | ||
29 | on a rectangular image. | ||
30 | |||
31 | It does neither know how to display its image nor about escape sequences. | ||
32 | It is further independent of the underlying toolkit. By this, one can even | ||
33 | use this module for an ordinary text surface. | ||
34 | |||
35 | Since the operations are called by a specific emulation decoder, one may | ||
36 | collect their different operations here. | ||
37 | |||
38 | The state manipulated by the operations is mainly kept in `image', though | ||
39 | it is a little more complex bejond this. See the header file of the class. | ||
40 | |||
41 | \sa TEWidget \sa VT102Emulation | ||
42 | */ | ||
43 | |||
44 | #include <stdio.h> | ||
45 | #include <stdlib.h> | ||
46 | #include <unistd.h> | ||
47 | // #include <kdebug.h> | ||
48 | |||
49 | #include <assert.h> | ||
50 | #include <string.h> | ||
51 | #include <ctype.h> | ||
52 | |||
53 | #include "screen.h" | ||
54 | |||
55 | #define HERE printf("%s(%d): here\n",__FILE__,__LINE__) | ||
56 | |||
57 | //FIXME: this is emulation specific. Use FALSE for xterm, TRUE for ANSI. | ||
58 | //FIXME: see if we can get this from terminfo. | ||
59 | #define BS_CLEARS FALSE | ||
60 | |||
61 | #define loc(X,Y) ((Y)*columns+(X)) | ||
62 | |||
63 | /*! creates a `Screen' of `lines' lines and `columns' columns. | ||
64 | */ | ||
65 | |||
66 | Screen::Screen(int lines, int columns) | ||
67 | { | ||
68 | this->lines = lines; | ||
69 | this->columns = columns; | ||
70 | |||
71 | image = (Character*) malloc(lines*columns*sizeof(Character)); | ||
72 | tabstops = NULL; initTabStops(); | ||
73 | |||
74 | histCursor = 0; | ||
75 | |||
76 | clearSelection(); | ||
77 | reset(); | ||
78 | } | ||
79 | |||
80 | /*! Destructor | ||
81 | */ | ||
82 | |||
83 | Screen::~Screen() | ||
84 | { | ||
85 | free(image); | ||
86 | if (tabstops) free(tabstops); | ||
87 | } | ||
88 | |||
89 | /* ------------------------------------------------------------------------- */ | ||
90 | /* */ | ||
91 | /* Normalized Screen Operations */ | ||
92 | /* */ | ||
93 | /* ------------------------------------------------------------------------- */ | ||
94 | |||
95 | // Cursor Setting -------------------------------------------------------------- | ||
96 | |||
97 | /*! \section Cursor | ||
98 | |||
99 | The `cursor' is a location within the screen that is implicitely used in | ||
100 | many operations. The operations within this section allow to manipulate | ||
101 | the cursor explicitly and to obtain it's value. | ||
102 | |||
103 | The position of the cursor is guarantied to be between (including) 0 and | ||
104 | `columns-1' and `lines-1'. | ||
105 | */ | ||
106 | |||
107 | /*! | ||
108 | Move the cursor up. | ||
109 | |||
110 | The cursor will not be moved beyond the top margin. | ||
111 | */ | ||
112 | |||
113 | void Screen::cursorUp(int n) | ||
114 | //=CUU | ||
115 | { | ||
116 | if (n == 0) n = 1; // Default | ||
117 | int stop = cuY < tmargin ? 0 : tmargin; | ||
118 | cuX = QMIN(columns-1,cuX); // nowrap! | ||
119 | cuY = QMAX(stop,cuY-n); | ||
120 | } | ||
121 | |||
122 | /*! | ||
123 | Move the cursor down. | ||
124 | |||
125 | The cursor will not be moved beyond the bottom margin. | ||
126 | */ | ||
127 | |||
128 | void Screen::cursorDown(int n) | ||
129 | //=CUD | ||
130 | { | ||
131 | if (n == 0) n = 1; // Default | ||
132 | int stop = cuY > bmargin ? lines-1 : bmargin; | ||
133 | cuX = QMIN(columns-1,cuX); // nowrap! | ||
134 | cuY = QMIN(stop,cuY+n); | ||
135 | } | ||
136 | |||
137 | /*! | ||
138 | Move the cursor left. | ||
139 | |||
140 | The cursor will not move beyond the first column. | ||
141 | */ | ||
142 | |||
143 | void Screen::cursorLeft(int n) | ||
144 | //=CUB | ||
145 | { | ||
146 | if (n == 0) n = 1; // Default | ||
147 | cuX = QMIN(columns-1,cuX); // nowrap! | ||
148 | cuX = QMAX(0,cuX-n); | ||
149 | } | ||
150 | |||
151 | /*! | ||
152 | Move the cursor left. | ||
153 | |||
154 | The cursor will not move beyond the rightmost column. | ||
155 | */ | ||
156 | |||
157 | void Screen::cursorRight(int n) | ||
158 | //=CUF | ||
159 | { | ||
160 | if (n == 0) n = 1; // Default | ||
161 | cuX = QMIN(columns-1,cuX+n); | ||
162 | } | ||
163 | |||
164 | /*! | ||
165 | Set top and bottom margin. | ||
166 | */ | ||
167 | |||
168 | void Screen::setMargins(int top, int bot) | ||
169 | //=STBM | ||
170 | { | ||
171 | if (top == 0) top = 1; // Default | ||
172 | if (bot == 0) bot = lines; // Default | ||
173 | top = top - 1; // Adjust to internal lineno | ||
174 | bot = bot - 1; // Adjust to internal lineno | ||
175 | if ( !( 0 <= top && top < bot && bot < lines ) ) | ||
176 | { fprintf(stderr,"%s(%d) : setRegion(%d,%d) : bad range.\n", | ||
177 | __FILE__,__LINE__,top,bot); | ||
178 | return; // Default error action: ignore | ||
179 | } | ||
180 | tmargin = top; | ||
181 | bmargin = bot; | ||
182 | cuX = 0; | ||
183 | cuY = getMode(MODE_Origin) ? top : 0; | ||
184 | } | ||
185 | |||
186 | /*! | ||
187 | Move the cursor down one line. | ||
188 | |||
189 | If cursor is on bottom margin, the region between the | ||
190 | actual top and bottom margin is scrolled up instead. | ||
191 | */ | ||
192 | |||
193 | void Screen::index() | ||
194 | //=IND | ||
195 | { | ||
196 | if (cuY == bmargin) | ||
197 | { | ||
198 | if (tmargin == 0 && bmargin == lines-1) addHistLine(); // hist.history | ||
199 | scrollUp(tmargin,1); | ||
200 | } | ||
201 | else if (cuY < lines-1) | ||
202 | cuY += 1; | ||
203 | } | ||
204 | |||
205 | /*! | ||
206 | Move the cursor up one line. | ||
207 | |||
208 | If cursor is on the top margin, the region between the | ||
209 | actual top and bottom margin is scrolled down instead. | ||
210 | */ | ||
211 | |||
212 | void Screen::reverseIndex() | ||
213 | //=RI | ||
214 | { | ||
215 | if (cuY == tmargin) | ||
216 | scrollDown(tmargin,1); | ||
217 | else if (cuY > 0) | ||
218 | cuY -= 1; | ||
219 | } | ||
220 | |||
221 | /*! | ||
222 | Move the cursor to the begin of the next line. | ||
223 | |||
224 | If cursor is on bottom margin, the region between the | ||
225 | actual top and bottom margin is scrolled up. | ||
226 | */ | ||
227 | |||
228 | void Screen::NextLine() | ||
229 | //=NEL | ||
230 | { | ||
231 | Return(); index(); | ||
232 | } | ||
233 | |||
234 | // Line Editing ---------------------------------------------------------------- | ||
235 | |||
236 | /*! \section inserting / deleting characters | ||
237 | */ | ||
238 | |||
239 | /*! erase `n' characters starting from (including) the cursor position. | ||
240 | |||
241 | The line is filled in from the right with spaces. | ||
242 | */ | ||
243 | |||
244 | void Screen::eraseChars(int n) | ||
245 | { | ||
246 | if (n == 0) n = 1; // Default | ||
247 | int p = QMAX(0,QMIN(cuX+n-1,columns-1)); | ||
248 | clearImage(loc(cuX,cuY),loc(p,cuY),' '); | ||
249 | } | ||
250 | |||
251 | /*! delete `n' characters starting from (including) the cursor position. | ||
252 | |||
253 | The line is filled in from the right with spaces. | ||
254 | */ | ||
255 | |||
256 | void Screen::deleteChars(int n) | ||
257 | { | ||
258 | if (n == 0) n = 1; // Default | ||
259 | int p = QMAX(0,QMIN(cuX+n,columns-1)); | ||
260 | moveImage(loc(cuX,cuY),loc(p,cuY),loc(columns-1,cuY)); | ||
261 | clearImage(loc(columns-n,cuY),loc(columns-1,cuY),' '); | ||
262 | } | ||
263 | |||
264 | /*! insert `n' spaces at the cursor position. | ||
265 | |||
266 | The cursor is not moved by the operation. | ||
267 | */ | ||
268 | |||
269 | void Screen::insertChars(int n) | ||
270 | { | ||
271 | if (n == 0) n = 1; // Default | ||
272 | int p = QMAX(0,QMIN(columns-1-n,columns-1)); | ||
273 | int q = QMAX(0,QMIN(cuX+n,columns-1)); | ||
274 | moveImage(loc(q,cuY),loc(cuX,cuY),loc(p,cuY)); | ||
275 | clearImage(loc(cuX,cuY),loc(q-1,cuY),' '); | ||
276 | } | ||
277 | |||
278 | /*! delete `n' lines starting from (including) the cursor position. | ||
279 | |||
280 | The cursor is not moved by the operation. | ||
281 | */ | ||
282 | |||
283 | void Screen::deleteLines(int n) | ||
284 | { | ||
285 | if (n == 0) n = 1; // Default | ||
286 | scrollUp(cuY,n); | ||
287 | } | ||
288 | |||
289 | /*! insert `n' lines at the cursor position. | ||
290 | |||
291 | The cursor is not moved by the operation. | ||
292 | */ | ||
293 | |||
294 | void Screen::insertLines(int n) | ||
295 | { | ||
296 | if (n == 0) n = 1; // Default | ||
297 | scrollDown(cuY,n); | ||
298 | } | ||
299 | |||
300 | // Mode Operations ----------------------------------------------------------- | ||
301 | |||
302 | /*! Set a specific mode. */ | ||
303 | |||
304 | void Screen::setMode(int m) | ||
305 | { | ||
306 | currParm.mode[m] = TRUE; | ||
307 | switch(m) | ||
308 | { | ||
309 | case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home | ||
310 | } | ||
311 | } | ||
312 | |||
313 | /*! Reset a specific mode. */ | ||
314 | |||
315 | void Screen::resetMode(int m) | ||
316 | { | ||
317 | currParm.mode[m] = FALSE; | ||
318 | switch(m) | ||
319 | { | ||
320 | case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home | ||
321 | } | ||
322 | } | ||
323 | |||
324 | /*! Save a specific mode. */ | ||
325 | |||
326 | void Screen::saveMode(int m) | ||
327 | { | ||
328 | saveParm.mode[m] = currParm.mode[m]; | ||
329 | } | ||
330 | |||
331 | /*! Restore a specific mode. */ | ||
332 | |||
333 | void Screen::restoreMode(int m) | ||
334 | { | ||
335 | currParm.mode[m] = saveParm.mode[m]; | ||
336 | } | ||
337 | |||
338 | //NOTE: this is a helper function | ||
339 | /*! Return the setting a specific mode. */ | ||
340 | BOOL Screen::getMode(int m) | ||
341 | { | ||
342 | return currParm.mode[m]; | ||
343 | } | ||
344 | |||
345 | /*! Save the cursor position and the rendition attribute settings. */ | ||
346 | |||
347 | void Screen::saveCursor() | ||
348 | { | ||
349 | sa_cuX = cuX; | ||
350 | sa_cuY = cuY; | ||
351 | sa_cu_re = cu_re; | ||
352 | sa_cu_fg = cu_fg; | ||
353 | sa_cu_bg = cu_bg; | ||
354 | } | ||
355 | |||
356 | /*! Restore the cursor position and the rendition attribute settings. */ | ||
357 | |||
358 | void Screen::restoreCursor() | ||
359 | { | ||
360 | cuX = QMIN(sa_cuX,columns-1); | ||
361 | cuY = QMIN(sa_cuY,lines-1); | ||
362 | cu_re = sa_cu_re; | ||
363 | cu_fg = sa_cu_fg; | ||
364 | cu_bg = sa_cu_bg; | ||
365 | effectiveRendition(); | ||
366 | } | ||
367 | |||
368 | /* ------------------------------------------------------------------------- */ | ||
369 | /* */ | ||
370 | /* Screen Operations */ | ||
371 | /* */ | ||
372 | /* ------------------------------------------------------------------------- */ | ||
373 | |||
374 | /*! Assing a new size to the screen. | ||
375 | |||
376 | The topmost left position is maintained, while lower lines | ||
377 | or right hand side columns might be removed or filled with | ||
378 | spaces to fit the new size. | ||
379 | |||
380 | The region setting is reset to the whole screen and the | ||
381 | tab positions reinitialized. | ||
382 | */ | ||
383 | |||
384 | void Screen::resizeImage(int new_lines, int new_columns) | ||
385 | { | ||
386 | |||
387 | if (cuY > new_lines-1) | ||
388 | { // attempt to preserve focus and lines | ||
389 | bmargin = lines-1; //FIXME: margin lost | ||
390 | for (int i = 0; i < cuY-(new_lines-1); i++) | ||
391 | { | ||
392 | addHistLine(); scrollUp(0,1); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | // make new image | ||
397 | Character* newimg = (Character*) malloc(new_lines*new_columns*sizeof(Character)); | ||
398 | |||
399 | clearSelection(); | ||
400 | |||
401 | // clear new image | ||
402 | for (int y = 0; y < new_lines; y++) | ||
403 | for (int x = 0; x < new_columns; x++) | ||
404 | { | ||
405 | newimg[y*new_columns+x].c = ' '; | ||
406 | newimg[y*new_columns+x].f = DEFAULT_FORE_COLOR; | ||
407 | newimg[y*new_columns+x].b = DEFAULT_BACK_COLOR; | ||
408 | newimg[y*new_columns+x].r = DEFAULT_RENDITION; | ||
409 | } | ||
410 | int cpy_lines = QMIN(new_lines, lines); | ||
411 | int cpy_columns = QMIN(new_columns,columns); | ||
412 | // copy to new image | ||
413 | for (int y = 0; y < cpy_lines; y++) | ||
414 | for (int x = 0; x < cpy_columns; x++) | ||
415 | { | ||
416 | newimg[y*new_columns+x].c = image[loc(x,y)].c; | ||
417 | newimg[y*new_columns+x].f = image[loc(x,y)].f; | ||
418 | newimg[y*new_columns+x].b = image[loc(x,y)].b; | ||
419 | newimg[y*new_columns+x].r = image[loc(x,y)].r; | ||
420 | } | ||
421 | free(image); | ||
422 | image = newimg; | ||
423 | lines = new_lines; | ||
424 | columns = new_columns; | ||
425 | cuX = QMIN(cuX,columns-1); | ||
426 | cuY = QMIN(cuY,lines-1); | ||
427 | |||
428 | // FIXME: try to keep values, evtl. | ||
429 | tmargin=0; | ||
430 | bmargin=lines-1; | ||
431 | initTabStops(); | ||
432 | clearSelection(); | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | Clarifying rendition here and in TEWidget. | ||
437 | |||
438 | currently, TEWidget's color table is | ||
439 | 0 1 2 .. 9 10 .. 17 | ||
440 | dft_fg, dft_bg, dim 0..7, intensive 0..7 | ||
441 | |||
442 | cu_fg, cu_bg contain values 0..8; | ||
443 | - 0 = default color | ||
444 | - 1..8 = ansi specified color | ||
445 | |||
446 | re_fg, re_bg contain values 0..17 | ||
447 | due to the TEWidget's color table | ||
448 | |||
449 | rendition attributes are | ||
450 | |||
451 | attr widget screen | ||
452 | -------------- ------ ------ | ||
453 | RE_UNDERLINE XX XX affects foreground only | ||
454 | RE_BLINK XX XX affects foreground only | ||
455 | RE_BOLD XX XX affects foreground only | ||
456 | RE_REVERSE -- XX | ||
457 | RE_TRANSPARENT XX -- affects background only | ||
458 | RE_INTENSIVE XX -- affects foreground only | ||
459 | |||
460 | Note that RE_BOLD is used in both widget | ||
461 | and screen rendition. Since xterm/vt102 | ||
462 | is to poor to distinguish between bold | ||
463 | (which is a font attribute) and intensive | ||
464 | (which is a color attribute), we translate | ||
465 | this and RE_BOLD in falls eventually appart | ||
466 | into RE_BOLD and RE_INTENSIVE. | ||
467 | */ | ||
468 | |||
469 | void Screen::reverseRendition(Character* p) | ||
470 | { UINT8 f = p->f; UINT8 b = p->b; | ||
471 | p->f = b; p->b = f; //p->r &= ~RE_TRANSPARENT; | ||
472 | } | ||
473 | |||
474 | void Screen::effectiveRendition() | ||
475 | // calculate rendition | ||
476 | { | ||
477 | ef_re = cu_re & (RE_UNDERLINE | RE_BLINK); | ||
478 | if (cu_re & RE_REVERSE) | ||
479 | { | ||
480 | ef_fg = cu_bg; | ||
481 | ef_bg = cu_fg; | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | ef_fg = cu_fg; | ||
486 | ef_bg = cu_bg; | ||
487 | } | ||
488 | if (cu_re & RE_BOLD) | ||
489 | { | ||
490 | if (ef_fg < BASE_COLORS) | ||
491 | ef_fg += BASE_COLORS; | ||
492 | else | ||
493 | ef_fg -= BASE_COLORS; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | /*! | ||
498 | returns the image. | ||
499 | |||
500 | Get the size of the image by \sa getLines and \sa getColumns. | ||
501 | |||
502 | NOTE that the image returned by this function must later be | ||
503 | freed. | ||
504 | |||
505 | */ | ||
506 | |||
507 | Character* Screen::getCookedImage() | ||
508 | { int x,y; | ||
509 | Character* merged = (Character*) malloc(lines*columns*sizeof(Character)); | ||
510 | Character dft(' ',DEFAULT_FORE_COLOR,DEFAULT_BACK_COLOR,DEFAULT_RENDITION); | ||
511 | |||
512 | for (y = 0; (y < lines) && (y < (hist.getLines()-histCursor)); y++) | ||
513 | { | ||
514 | int len = QMIN(columns,hist.getLineLen(y+histCursor)); | ||
515 | int yp = y*columns; | ||
516 | int yq = (y+histCursor)*columns; | ||
517 | |||
518 | hist.getCells(y+histCursor,0,len,merged+yp); | ||
519 | for (x = len; x < columns; x++) merged[yp+x] = dft; | ||
520 | for (x = 0; x < columns; x++) | ||
521 | { int p=x + yp; int q=x + yq; | ||
522 | if ( ( q >= sel_TL ) && ( q <= sel_BR ) ) | ||
523 | reverseRendition(&merged[p]); // for selection | ||
524 | } | ||
525 | } | ||
526 | if (lines >= hist.getLines()-histCursor) | ||
527 | { | ||
528 | for (y = (hist.getLines()-histCursor); y < lines ; y++) | ||
529 | { | ||
530 | int yp = y*columns; | ||
531 | int yq = (y+histCursor)*columns; | ||
532 | int yr = (y-hist.getLines()+histCursor)*columns; | ||
533 | for (x = 0; x < columns; x++) | ||
534 | { int p = x + yp; int q = x + yq; int r = x + yr; | ||
535 | merged[p] = image[r]; | ||
536 | if ( q >= sel_TL && q <= sel_BR ) | ||
537 | reverseRendition(&merged[p]); // for selection | ||
538 | } | ||
539 | |||
540 | } | ||
541 | } | ||
542 | // evtl. inverse display | ||
543 | if (getMode(MODE_Screen)) | ||
544 | { int i,n = lines*columns; | ||
545 | for (i = 0; i < n; i++) | ||
546 | reverseRendition(&merged[i]); // for reverse display | ||
547 | } | ||
548 | if (getMode(MODE_Cursor) && (cuY+(hist.getLines()-histCursor) < lines)) // cursor visible | ||
549 | reverseRendition(&merged[loc(cuX,cuY+(hist.getLines()-histCursor))]); | ||
550 | return merged; | ||
551 | } | ||
552 | |||
553 | |||
554 | /*! | ||
555 | */ | ||
556 | |||
557 | void Screen::reset() | ||
558 | { | ||
559 | setMode(MODE_Wrap ); saveMode(MODE_Wrap ); // wrap at end of margin | ||
560 | resetMode(MODE_Origin); saveMode(MODE_Origin); // position refere to [1,1] | ||
561 | resetMode(MODE_Insert); saveMode(MODE_Insert); // overstroke | ||
562 | setMode(MODE_Cursor); // cursor visible | ||
563 | resetMode(MODE_Screen); // screen not inverse | ||
564 | resetMode(MODE_NewLine); | ||
565 | |||
566 | tmargin=0; | ||
567 | bmargin=lines-1; | ||
568 | |||
569 | setDefaultRendition(); | ||
570 | saveCursor(); | ||
571 | |||
572 | clear(); | ||
573 | } | ||
574 | |||
575 | /*! Clear the entire screen and home the cursor. | ||
576 | */ | ||
577 | |||
578 | void Screen::clear() | ||
579 | { | ||
580 | clearEntireScreen(); | ||
581 | home(); | ||
582 | } | ||
583 | |||
584 | /*! Moves the cursor left one column. | ||
585 | */ | ||
586 | |||
587 | void Screen::BackSpace() | ||
588 | { | ||
589 | cuX = QMAX(0,cuX-1); | ||
590 | if (BS_CLEARS) image[loc(cuX,cuY)].c = ' '; | ||
591 | } | ||
592 | |||
593 | /*! | ||
594 | */ | ||
595 | |||
596 | void Screen::Tabulate() | ||
597 | { | ||
598 | // note that TAB is a format effector (does not write ' '); | ||
599 | cursorRight(1); while(cuX < columns-1 && !tabstops[cuX]) cursorRight(1); | ||
600 | } | ||
601 | |||
602 | void Screen::clearTabStops() | ||
603 | { | ||
604 | for (int i = 0; i < columns; i++) tabstops[i-1] = FALSE; | ||
605 | } | ||
606 | |||
607 | void Screen::changeTabStop(bool set) | ||
608 | { | ||
609 | if (cuX >= columns) return; | ||
610 | tabstops[cuX] = set; | ||
611 | } | ||
612 | |||
613 | void Screen::initTabStops() | ||
614 | { | ||
615 | if (tabstops) free(tabstops); | ||
616 | tabstops = (bool*)malloc(columns*sizeof(bool)); | ||
617 | // Arrg! The 1st tabstop has to be one longer than the other. | ||
618 | // i.e. the kids start counting from 0 instead of 1. | ||
619 | // Other programs might behave correctly. Be aware. | ||
620 | for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0); | ||
621 | } | ||
622 | |||
623 | /*! | ||
624 | This behaves either as IND (Screen::Index) or as NEL (Screen::NextLine) | ||
625 | depending on the NewLine Mode (LNM). This mode also | ||
626 | affects the key sequence returned for newline ([CR]LF). | ||
627 | */ | ||
628 | |||
629 | void Screen::NewLine() | ||
630 | { | ||
631 | if (getMode(MODE_NewLine)) Return(); | ||
632 | index(); | ||
633 | } | ||
634 | |||
635 | /*! put `c' literally onto the screen at the current cursor position. | ||
636 | |||
637 | VT100 uses the convention to produce an automatic newline (am) | ||
638 | with the *first* character that would fall onto the next line (xenl). | ||
639 | */ | ||
640 | |||
641 | void Screen::checkSelection(int from, int to) | ||
642 | { | ||
643 | if (sel_begin == -1) return; | ||
644 | int scr_TL = loc(0, hist.getLines()); | ||
645 | //Clear entire selection if it overlaps region [from, to] | ||
646 | if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) ) | ||
647 | { | ||
648 | clearSelection(); | ||
649 | } | ||
650 | } | ||
651 | |||
652 | void Screen::ShowCharacter(unsigned short c) | ||
653 | { | ||
654 | // Note that VT100 does wrapping BEFORE putting the character. | ||
655 | // This has impact on the assumption of valid cursor positions. | ||
656 | // We indicate the fact that a newline has to be triggered by | ||
657 | // putting the cursor one right to the last column of the screen. | ||
658 | |||
659 | if (cuX >= columns) | ||
660 | { | ||
661 | if (getMode(MODE_Wrap)) NextLine(); else cuX = columns-1; | ||
662 | } | ||
663 | |||
664 | if (getMode(MODE_Insert)) insertChars(1); | ||
665 | |||
666 | int i = loc(cuX,cuY); | ||
667 | |||
668 | checkSelection(i, i); // check if selection is still valid. | ||
669 | |||
670 | image[i].c = c; | ||
671 | image[i].f = ef_fg; | ||
672 | image[i].b = ef_bg; | ||
673 | image[i].r = ef_re; | ||
674 | |||
675 | cuX += 1; | ||
676 | } | ||
677 | |||
678 | // Region commands ------------------------------------------------------------- | ||
679 | |||
680 | |||
681 | /*! scroll up `n' lines within current region. | ||
682 | The `n' new lines are cleared. | ||
683 | \sa setRegion \sa scrollDown | ||
684 | */ | ||
685 | |||
686 | void Screen::scrollUp(int from, int n) | ||
687 | { | ||
688 | if (n <= 0 || from + n > bmargin) return; | ||
689 | //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. | ||
690 | moveImage(loc(0,from),loc(0,from+n),loc(columns-1,bmargin)); | ||
691 | clearImage(loc(0,bmargin-n+1),loc(columns-1,bmargin),' '); | ||
692 | } | ||
693 | |||
694 | /*! scroll down `n' lines within current region. | ||
695 | The `n' new lines are cleared. | ||
696 | \sa setRegion \sa scrollUp | ||
697 | */ | ||
698 | |||
699 | void Screen::scrollDown(int from, int n) | ||
700 | { | ||
701 | //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. | ||
702 | if (n <= 0) return; | ||
703 | if (from > bmargin) return; | ||
704 | if (from + n > bmargin) n = bmargin - from; | ||
705 | moveImage(loc(0,from+n),loc(0,from),loc(columns-1,bmargin-n)); | ||
706 | clearImage(loc(0,from),loc(columns-1,from+n-1),' '); | ||
707 | } | ||
708 | |||
709 | /*! position the cursor to a specific line and column. */ | ||
710 | void Screen::setCursorYX(int y, int x) | ||
711 | { | ||
712 | setCursorY(y); setCursorX(x); | ||
713 | } | ||
714 | |||
715 | /*! Set the cursor to x-th line. */ | ||
716 | |||
717 | void Screen::setCursorX(int x) | ||
718 | { | ||
719 | if (x == 0) x = 1; // Default | ||
720 | x -= 1; // Adjust | ||
721 | cuX = QMAX(0,QMIN(columns-1, x)); | ||
722 | } | ||
723 | |||
724 | /*! Set the cursor to y-th line. */ | ||
725 | |||
726 | void Screen::setCursorY(int y) | ||
727 | { | ||
728 | if (y == 0) y = 1; // Default | ||
729 | y -= 1; // Adjust | ||
730 | cuY = QMAX(0,QMIN(lines -1, y + (getMode(MODE_Origin) ? tmargin : 0) )); | ||
731 | } | ||
732 | |||
733 | /*! set cursor to the `left upper' corner of the screen (1,1). | ||
734 | */ | ||
735 | |||
736 | void Screen::home() | ||
737 | { | ||
738 | cuX = 0; | ||
739 | cuY = 0; | ||
740 | } | ||
741 | |||
742 | /*! set cursor to the begin of the current line. | ||
743 | */ | ||
744 | |||
745 | void Screen::Return() | ||
746 | { | ||
747 | cuX = 0; | ||
748 | } | ||
749 | |||
750 | /*! returns the current cursor columns. | ||
751 | */ | ||
752 | |||
753 | int Screen::getCursorX() | ||
754 | { | ||
755 | return cuX; | ||
756 | } | ||
757 | |||
758 | /*! returns the current cursor line. | ||
759 | */ | ||
760 | |||
761 | int Screen::getCursorY() | ||
762 | { | ||
763 | return cuY; | ||
764 | } | ||
765 | |||
766 | // Erasing --------------------------------------------------------------------- | ||
767 | |||
768 | /*! \section Erasing | ||
769 | |||
770 | This group of operations erase parts of the screen contents by filling | ||
771 | it with spaces colored due to the current rendition settings. | ||
772 | |||
773 | Althought the cursor position is involved in most of these operations, | ||
774 | it is never modified by them. | ||
775 | */ | ||
776 | |||
777 | /*! fill screen between (including) `loca' and `loce' with spaces. | ||
778 | |||
779 | This is an internal helper functions. The parameter types are internal | ||
780 | addresses of within the screen image and make use of the way how the | ||
781 | screen matrix is mapped to the image vector. | ||
782 | */ | ||
783 | |||
784 | void Screen::clearImage(int loca, int loce, char c) | ||
785 | { int i; | ||
786 | int scr_TL=loc(0,hist.getLines()); | ||
787 | //FIXME: check positions | ||
788 | |||
789 | //Clear entire selection if it overlaps region to be moved... | ||
790 | if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) ) | ||
791 | { | ||
792 | clearSelection(); | ||
793 | } | ||
794 | for (i = loca; i <= loce; i++) | ||
795 | { | ||
796 | image[i].c = c; | ||
797 | image[i].f = ef_fg; //DEFAULT_FORE_COLOR; //FIXME: xterm and linux/ansi | ||
798 | image[i].b = ef_bg; //DEFAULT_BACK_COLOR; // many have different | ||
799 | image[i].r = ef_re; //DEFAULT_RENDITION; // ideas here. | ||
800 | } | ||
801 | } | ||
802 | |||
803 | /*! move image between (including) `loca' and `loce' to 'dst'. | ||
804 | |||
805 | This is an internal helper functions. The parameter types are internal | ||
806 | addresses of within the screen image and make use of the way how the | ||
807 | screen matrix is mapped to the image vector. | ||
808 | */ | ||
809 | |||
810 | void Screen::moveImage(int dst, int loca, int loce) | ||
811 | { | ||
812 | //FIXME: check positions | ||
813 | if (loce < loca) { | ||
814 | // kdDebug() << "WARNING!!! call to Screen:moveImage with loce < loca!" << endl; | ||
815 | return; | ||
816 | } | ||
817 | memmove(&image[dst],&image[loca],(loce-loca+1)*sizeof(Character)); | ||
818 | } | ||
819 | |||
820 | /*! clear from (including) current cursor position to end of screen. | ||
821 | */ | ||
822 | |||
823 | void Screen::clearToEndOfScreen() | ||
824 | { | ||
825 | clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' '); | ||
826 | } | ||
827 | |||
828 | /*! clear from begin of screen to (including) current cursor position. | ||
829 | */ | ||
830 | |||
831 | void Screen::clearToBeginOfScreen() | ||
832 | { | ||
833 | clearImage(loc(0,0),loc(cuX,cuY),' '); | ||
834 | } | ||
835 | |||
836 | /*! clear the entire screen. | ||
837 | */ | ||
838 | |||
839 | void Screen::clearEntireScreen() | ||
840 | { | ||
841 | clearImage(loc(0,0),loc(columns-1,lines-1),' '); | ||
842 | } | ||
843 | |||
844 | /*! fill screen with 'E' | ||
845 | This is to aid screen alignment | ||
846 | */ | ||
847 | |||
848 | void Screen::helpAlign() | ||
849 | { | ||
850 | clearImage(loc(0,0),loc(columns-1,lines-1),'E'); | ||
851 | } | ||
852 | |||
853 | /*! clear from (including) current cursor position to end of current cursor line. | ||
854 | */ | ||
855 | |||
856 | void Screen::clearToEndOfLine() | ||
857 | { | ||
858 | clearImage(loc(cuX,cuY),loc(columns-1,cuY),' '); | ||
859 | } | ||
860 | |||
861 | /*! clear from begin of current cursor line to (including) current cursor position. | ||
862 | */ | ||
863 | |||
864 | void Screen::clearToBeginOfLine() | ||
865 | { | ||
866 | clearImage(loc(0,cuY),loc(cuX,cuY),' '); | ||
867 | } | ||
868 | |||
869 | /*! clears entire current cursor line | ||
870 | */ | ||
871 | |||
872 | void Screen::clearEntireLine() | ||
873 | { | ||
874 | clearImage(loc(0,cuY),loc(columns-1,cuY),' '); | ||
875 | } | ||
876 | |||
877 | // Rendition ------------------------------------------------------------------ | ||
878 | |||
879 | /*! | ||
880 | set rendition mode | ||
881 | */ | ||
882 | |||
883 | void Screen::setRendition(int re) | ||
884 | { | ||
885 | cu_re |= re; | ||
886 | effectiveRendition(); | ||
887 | } | ||
888 | |||
889 | /*! | ||
890 | reset rendition mode | ||
891 | */ | ||
892 | |||
893 | void Screen::resetRendition(int re) | ||
894 | { | ||
895 | cu_re &= ~re; | ||
896 | effectiveRendition(); | ||
897 | } | ||
898 | |||
899 | /*! | ||
900 | */ | ||
901 | |||
902 | void Screen::setDefaultRendition() | ||
903 | { | ||
904 | setForeColorToDefault(); | ||
905 | setBackColorToDefault(); | ||
906 | cu_re = DEFAULT_RENDITION; | ||
907 | effectiveRendition(); | ||
908 | } | ||
909 | |||
910 | /*! | ||
911 | */ | ||
912 | |||
913 | void Screen::setForeColor(int fgcolor) | ||
914 | { | ||
915 | cu_fg = (fgcolor&7)+((fgcolor&8) ? 4+8 : 2); | ||
916 | effectiveRendition(); | ||
917 | } | ||
918 | |||
919 | /*! | ||
920 | */ | ||
921 | |||
922 | void Screen::setBackColor(int bgcolor) | ||
923 | { | ||
924 | cu_bg = (bgcolor&7)+((bgcolor&8) ? 4+8 : 2); | ||
925 | effectiveRendition(); | ||
926 | } | ||
927 | |||
928 | /*! | ||
929 | */ | ||
930 | |||
931 | void Screen::setBackColorToDefault() | ||
932 | { | ||
933 | cu_bg = DEFAULT_BACK_COLOR; | ||
934 | effectiveRendition(); | ||
935 | } | ||
936 | |||
937 | /*! | ||
938 | */ | ||
939 | |||
940 | void Screen::setForeColorToDefault() | ||
941 | { | ||
942 | cu_fg = DEFAULT_FORE_COLOR; | ||
943 | effectiveRendition(); | ||
944 | } | ||
945 | |||
946 | /* ------------------------------------------------------------------------- */ | ||
947 | /* */ | ||
948 | /* Marking & Selection */ | ||
949 | /* */ | ||
950 | /* ------------------------------------------------------------------------- */ | ||
951 | |||
952 | void Screen::clearSelection() | ||
953 | { | ||
954 | sel_BR = -1; | ||
955 | sel_TL = -1; | ||
956 | sel_begin = -1; | ||
957 | } | ||
958 | |||
959 | void Screen::setSelBeginXY(const int x, const int y) | ||
960 | { | ||
961 | sel_begin = loc(x,y+histCursor) ; | ||
962 | sel_BR = sel_begin; | ||
963 | sel_TL = sel_begin; | ||
964 | } | ||
965 | |||
966 | void Screen::setSelExtentXY(const int x, const int y) | ||
967 | { | ||
968 | if (sel_begin == -1) return; | ||
969 | int l = loc(x,y + histCursor); | ||
970 | |||
971 | if (l < sel_begin) | ||
972 | { | ||
973 | sel_TL = l; | ||
974 | sel_BR = sel_begin; | ||
975 | } | ||
976 | else | ||
977 | { | ||
978 | /* FIXME, HACK to correct for x too far to the right... */ | ||
979 | if (( x == columns )|| (x == 0)) l--; | ||
980 | |||
981 | sel_TL = sel_begin; | ||
982 | sel_BR = l; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | QString Screen::getSelText(const BOOL preserve_line_breaks) | ||
987 | { | ||
988 | if (sel_begin == -1) | ||
989 | return QString::null; // Selection got clear while selecting. | ||
990 | |||
991 | int *m; // buffer to fill. | ||
992 | int s, d; // source index, dest. index. | ||
993 | int hist_BR = loc(0, hist.getLines()); | ||
994 | int hY = sel_TL / columns; | ||
995 | int hX = sel_TL % columns; | ||
996 | int eol; // end of line | ||
997 | |||
998 | s = sel_TL; // tracks copy in source. | ||
999 | |||
1000 | // allocate buffer for maximum | ||
1001 | // possible size... | ||
1002 | d = (sel_BR - sel_TL) / columns + 1; | ||
1003 | m = new int[d * (columns + 1) + 2]; | ||
1004 | d = 0; | ||
1005 | |||
1006 | while (s <= sel_BR) | ||
1007 | { | ||
1008 | if (s < hist_BR) | ||
1009 | { // get lines from hist.history | ||
1010 | // buffer. | ||
1011 | eol = hist.getLineLen(hY); | ||
1012 | |||
1013 | if ((hY == (sel_BR / columns)) && | ||
1014 | (eol >= (sel_BR % columns))) | ||
1015 | { | ||
1016 | eol = sel_BR % columns + 1; | ||
1017 | } | ||
1018 | |||
1019 | while (hX < eol) | ||
1020 | { | ||
1021 | m[d++] = hist.getCell(hY, hX++).c; | ||
1022 | s++; | ||
1023 | } | ||
1024 | |||
1025 | if (s <= sel_BR) | ||
1026 | { | ||
1027 | // The line break handling | ||
1028 | // It's different from the screen | ||
1029 | // image case! | ||
1030 | if (eol % columns == 0) | ||
1031 | { | ||
1032 | // That's either a completely filled | ||
1033 | // line or an empty line | ||
1034 | if (eol == 0) | ||
1035 | { | ||
1036 | m[d++] = '\n'; | ||
1037 | } | ||
1038 | else | ||
1039 | { | ||
1040 | // We have a full line. | ||
1041 | // FIXME: How can we handle newlines | ||
1042 | // at this position?! | ||
1043 | } | ||
1044 | } | ||
1045 | else if ((eol + 1) % columns == 0) | ||
1046 | { | ||
1047 | // FIXME: We don't know if this was a | ||
1048 | // space at the last position or a | ||
1049 | // short line!! | ||
1050 | m[d++] = ' '; | ||
1051 | } | ||
1052 | else | ||
1053 | { | ||
1054 | // We have a short line here. Put a | ||
1055 | // newline or a space into the | ||
1056 | // buffer. | ||
1057 | m[d++] = preserve_line_breaks ? '\n' : ' '; | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | hY++; | ||
1062 | hX = 0; | ||
1063 | s = hY * columns; | ||
1064 | } | ||
1065 | else | ||
1066 | { // or from screen image. | ||
1067 | eol = (s / columns + 1) * columns - 1; | ||
1068 | |||
1069 | if (eol < sel_BR) | ||
1070 | { | ||
1071 | while ((eol > s) && | ||
1072 | isspace(image[eol - hist_BR].c)) | ||
1073 | { | ||
1074 | eol--; | ||
1075 | } | ||
1076 | } | ||
1077 | else | ||
1078 | { | ||
1079 | eol = sel_BR; | ||
1080 | } | ||
1081 | |||
1082 | while (s <= eol) | ||
1083 | { | ||
1084 | m[d++] = image[s++ - hist_BR].c; | ||
1085 | } | ||
1086 | |||
1087 | if (eol < sel_BR) | ||
1088 | { | ||
1089 | // eol processing see below ... | ||
1090 | if ((eol + 1) % columns == 0) | ||
1091 | { | ||
1092 | if (image[eol - hist_BR].c == ' ') | ||
1093 | { | ||
1094 | m[d++] = ' '; | ||
1095 | } | ||
1096 | } | ||
1097 | else | ||
1098 | { | ||
1099 | m[d++] = ((preserve_line_breaks || | ||
1100 | ((eol % columns) == 0)) ? | ||
1101 | '\n' : ' '); | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1105 | s = (eol / columns + 1) * columns; | ||
1106 | } | ||
1107 | } | ||
1108 | |||
1109 | QChar* qc = new QChar[d]; | ||
1110 | |||
1111 | for (int i = 0; i < d; i++) | ||
1112 | { | ||
1113 | qc[i] = m[i]; | ||
1114 | } | ||
1115 | |||
1116 | QString res(qc, d); | ||
1117 | |||
1118 | delete m; | ||
1119 | delete qc; | ||
1120 | |||
1121 | return res; | ||
1122 | } | ||
1123 | /* above ... end of line processing for selection -- psilva | ||
1124 | cases: | ||
1125 | |||
1126 | 1) (eol+1)%columns == 0 --> the whole line is filled. | ||
1127 | If the last char is a space, insert (preserve) space. otherwise | ||
1128 | leave the text alone, so that words that are broken by linewrap | ||
1129 | are preserved. | ||
1130 | |||
1131 | FIXME: | ||
1132 | * this suppresses \n for command output that is | ||
1133 | sized to the exact column width of the screen. | ||
1134 | |||
1135 | 2) eol%columns == 0 --> blank line. | ||
1136 | insert a \n unconditionally. | ||
1137 | Do it either you would because you are in preserve_line_break mode, | ||
1138 | or because it's an ASCII paragraph delimiter, so even when | ||
1139 | not preserving line_breaks, you want to preserve paragraph breaks. | ||
1140 | |||
1141 | 3) else --> partially filled line | ||
1142 | insert a \n in preserve line break mode, else a space | ||
1143 | The space prevents concatenation of the last word of one | ||
1144 | line with the first of the next. | ||
1145 | |||
1146 | */ | ||
1147 | |||
1148 | void Screen::addHistLine() | ||
1149 | { | ||
1150 | assert(hasScroll() || histCursor == 0); | ||
1151 | |||
1152 | // add to hist buffer | ||
1153 | // we have to take care about scrolling, too... | ||
1154 | |||
1155 | if (hasScroll()) | ||
1156 | { Character dft; | ||
1157 | |||
1158 | int end = columns-1; | ||
1159 | while (end >= 0 && image[end] == dft) | ||
1160 | end -= 1; | ||
1161 | |||
1162 | hist.addCells(image,end+1); | ||
1163 | hist.addLine(); | ||
1164 | |||
1165 | // adjust history cursor | ||
1166 | histCursor += (hist.getLines()-1 == histCursor); | ||
1167 | } | ||
1168 | |||
1169 | if (!hasScroll()) histCursor = 0; //FIXME: a poor workaround | ||
1170 | } | ||
1171 | |||
1172 | void Screen::setHistCursor(int cursor) | ||
1173 | { | ||
1174 | histCursor = cursor; //FIXME:rangecheck | ||
1175 | } | ||
1176 | |||
1177 | int Screen::getHistCursor() | ||
1178 | { | ||
1179 | return histCursor; | ||
1180 | } | ||
1181 | |||
1182 | int Screen::getHistLines() | ||
1183 | { | ||
1184 | return hist.getLines(); | ||
1185 | } | ||
1186 | |||
1187 | void Screen::setScroll(bool on) | ||
1188 | { | ||
1189 | histCursor = 0; | ||
1190 | clearSelection(); | ||
1191 | hist.setScroll(on); | ||
1192 | } | ||
1193 | |||
1194 | bool Screen::hasScroll() | ||
1195 | { | ||
1196 | return hist.hasScroll(); | ||
1197 | } | ||
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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [screen.h] Screen Data Type */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | #ifndef SCREEN_H | ||
20 | #define SCREEN_H | ||
21 | |||
22 | /*! \file | ||
23 | */ | ||
24 | |||
25 | #include "common.h" | ||
26 | #include "history.h" | ||
27 | |||
28 | #define MODE_Origin 0 | ||
29 | #define MODE_Wrap 1 | ||
30 | #define MODE_Insert 2 | ||
31 | #define MODE_Screen 3 | ||
32 | #define MODE_Cursor 4 | ||
33 | #define MODE_NewLine 5 | ||
34 | #define MODES_SCREEN 6 | ||
35 | |||
36 | /*! | ||
37 | */ | ||
38 | struct ScreenParm | ||
39 | { | ||
40 | int mode[MODES_SCREEN]; | ||
41 | }; | ||
42 | |||
43 | |||
44 | class Screen | ||
45 | { | ||
46 | public: | ||
47 | Screen(int lines, int columns); | ||
48 | ~Screen(); | ||
49 | |||
50 | public: // these are all `Screen' operations | ||
51 | // | ||
52 | // VT100/2 Operations ------------------ | ||
53 | // | ||
54 | // Cursor Movement | ||
55 | // | ||
56 | void cursorUp (int n); | ||
57 | void cursorDown (int n); | ||
58 | void cursorLeft (int n); | ||
59 | void cursorRight (int n); | ||
60 | void setCursorY (int y); | ||
61 | void setCursorX (int x); | ||
62 | void setCursorYX (int y, int x); | ||
63 | void setMargins (int t, int b); | ||
64 | // | ||
65 | // Cursor Movement with Scrolling | ||
66 | // | ||
67 | void NewLine (); | ||
68 | void NextLine (); | ||
69 | void index (); | ||
70 | void reverseIndex(); | ||
71 | // | ||
72 | void Return (); | ||
73 | void BackSpace (); | ||
74 | void Tabulate (); | ||
75 | // | ||
76 | // Editing | ||
77 | // | ||
78 | void eraseChars (int n); | ||
79 | void deleteChars (int n); | ||
80 | void insertChars (int n); | ||
81 | void deleteLines (int n); | ||
82 | void insertLines (int n); | ||
83 | // | ||
84 | // ------------------------------------- | ||
85 | // | ||
86 | void clearTabStops(); | ||
87 | void changeTabStop(bool set); | ||
88 | // | ||
89 | void resetMode (int n); | ||
90 | void setMode (int n); | ||
91 | void saveMode (int n); | ||
92 | void restoreMode (int n); | ||
93 | // | ||
94 | void saveCursor (); | ||
95 | void restoreCursor(); | ||
96 | // | ||
97 | // ------------------------------------- | ||
98 | // | ||
99 | void clearEntireScreen(); | ||
100 | void clearToEndOfScreen(); | ||
101 | void clearToBeginOfScreen(); | ||
102 | // | ||
103 | void clearEntireLine(); | ||
104 | void clearToEndOfLine(); | ||
105 | void clearToBeginOfLine(); | ||
106 | // | ||
107 | void helpAlign (); | ||
108 | // | ||
109 | // ------------------------------------- | ||
110 | // | ||
111 | void setRendition (int rendition); | ||
112 | void resetRendition(int rendition); | ||
113 | void setForeColor (int fgcolor); | ||
114 | void setBackColor (int bgcolor); | ||
115 | // | ||
116 | void setDefaultRendition(); | ||
117 | void setForeColorToDefault(); | ||
118 | void setBackColorToDefault(); | ||
119 | // | ||
120 | // ------------------------------------- | ||
121 | // | ||
122 | BOOL getMode (int n); | ||
123 | // | ||
124 | // only for report cursor position | ||
125 | // | ||
126 | int getCursorX(); | ||
127 | int getCursorY(); | ||
128 | // | ||
129 | // ------------------------------------- | ||
130 | // | ||
131 | void clear(); | ||
132 | void home(); | ||
133 | void reset(); | ||
134 | // | ||
135 | void ShowCharacter(unsigned short c); | ||
136 | // | ||
137 | void resizeImage(int new_lines, int new_columns); | ||
138 | // | ||
139 | Character* getCookedImage(); | ||
140 | |||
141 | /*! return the number of lines. */ | ||
142 | int getLines() { return lines; } | ||
143 | /*! return the number of columns. */ | ||
144 | int getColumns() { return columns; } | ||
145 | |||
146 | /*! set the position of the history cursor. */ | ||
147 | void setHistCursor(int cursor); | ||
148 | /*! return the position of the history cursor. */ | ||
149 | int getHistCursor(); | ||
150 | |||
151 | int getHistLines (); | ||
152 | void setScroll(bool on); | ||
153 | bool hasScroll(); | ||
154 | |||
155 | // | ||
156 | // Selection | ||
157 | // | ||
158 | void setSelBeginXY(const int x, const int y); | ||
159 | void setSelExtentXY(const int x, const int y); | ||
160 | void clearSelection(); | ||
161 | QString getSelText(const BOOL preserve_line_breaks); | ||
162 | |||
163 | void checkSelection(int from, int to); | ||
164 | |||
165 | private: // helper | ||
166 | |||
167 | void clearImage(int loca, int loce, char c); | ||
168 | void moveImage(int dst, int loca, int loce); | ||
169 | |||
170 | void scrollUp(int from, int i); | ||
171 | void scrollDown(int from, int i); | ||
172 | |||
173 | void addHistLine(); | ||
174 | |||
175 | void initTabStops(); | ||
176 | |||
177 | void effectiveRendition(); | ||
178 | void reverseRendition(Character* p); | ||
179 | |||
180 | private: | ||
181 | |||
182 | /* | ||
183 | The state of the screen is more complex as one would | ||
184 | expect first. The screem does really do part of the | ||
185 | emulation providing state informations in form of modes, | ||
186 | margins, tabulators, cursor etc. | ||
187 | |||
188 | Even more unexpected are variables to save and restore | ||
189 | parts of the state. | ||
190 | */ | ||
191 | |||
192 | // screen image ---------------- | ||
193 | |||
194 | int lines; | ||
195 | int columns; | ||
196 | Character *image; // [lines][columns] | ||
197 | |||
198 | // history buffer --------------- | ||
199 | |||
200 | int histCursor; // display position relative to start of the history buffer | ||
201 | HistoryScroll hist; | ||
202 | |||
203 | // cursor location | ||
204 | |||
205 | int cuX; | ||
206 | int cuY; | ||
207 | |||
208 | // cursor color and rendition info | ||
209 | |||
210 | UINT8 cu_fg; // foreground | ||
211 | UINT8 cu_bg; // background | ||
212 | UINT8 cu_re; // rendition | ||
213 | |||
214 | // margins ---------------- | ||
215 | |||
216 | int tmargin; // top margin | ||
217 | int bmargin; // bottom margin | ||
218 | |||
219 | // states ---------------- | ||
220 | |||
221 | ScreenParm currParm; | ||
222 | |||
223 | // ---------------------------- | ||
224 | |||
225 | bool* tabstops; | ||
226 | |||
227 | // selection ------------------- | ||
228 | |||
229 | int sel_begin; // The first location selected. | ||
230 | int sel_TL; // TopLeft Location. | ||
231 | int sel_BR; // Bottom Right Location. | ||
232 | |||
233 | // effective colors and rendition ------------ | ||
234 | |||
235 | UINT8 ef_fg; // These are derived from | ||
236 | UINT8 ef_bg; // the cu_* variables above | ||
237 | UINT8 ef_re; // to speed up operation | ||
238 | |||
239 | // | ||
240 | // save cursor, rendition & states ------------ | ||
241 | // | ||
242 | |||
243 | // cursor location | ||
244 | |||
245 | int sa_cuX; | ||
246 | int sa_cuY; | ||
247 | |||
248 | // rendition info | ||
249 | |||
250 | UINT8 sa_cu_re; | ||
251 | UINT8 sa_cu_fg; | ||
252 | UINT8 sa_cu_bg; | ||
253 | |||
254 | // modes | ||
255 | |||
256 | ScreenParm saveParm; | ||
257 | }; | ||
258 | |||
259 | #endif // TESCREEN_H | ||
diff --git a/noncore/apps/opie-console/screen.o b/noncore/apps/opie-console/screen.o new file mode 100644 index 0000000..b2d0420 --- a/dev/null +++ b/noncore/apps/opie-console/screen.o | |||
Binary files differ | |||
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 @@ | |||
1 | /* ------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [vt102emulation.cpp] VT102 Terminal Emulation */ | ||
4 | /* */ | ||
5 | /* ------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* ------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | |||
19 | /*! \class Vt102Emulation | ||
20 | |||
21 | \brief Actual Emulation for Konsole | ||
22 | |||
23 | \sa Widget \sa Screen \sa EmulationLayer | ||
24 | */ | ||
25 | |||
26 | #include "vt102emulation.h" | ||
27 | #include "widget.h" | ||
28 | #include "screen.h" | ||
29 | #include "keytrans.h" | ||
30 | |||
31 | #include <stdio.h> | ||
32 | #include <unistd.h> | ||
33 | #include <qkeycode.h> | ||
34 | #include <qtextcodec.h> | ||
35 | |||
36 | |||
37 | /* VT102 Terminal Emulation | ||
38 | |||
39 | This class puts together the screens, the pty and the widget to a | ||
40 | complete terminal emulation. Beside combining it's componentes, it | ||
41 | handles the emulations's protocol. | ||
42 | |||
43 | This module consists of the following sections: | ||
44 | |||
45 | - Constructor/Destructor | ||
46 | - Incoming Bytes Event pipeline | ||
47 | - Outgoing Bytes | ||
48 | - Mouse Events | ||
49 | - Keyboard Events | ||
50 | - Modes and Charset State | ||
51 | - Diagnostics | ||
52 | */ | ||
53 | |||
54 | |||
55 | /* ------------------------------------------------------------------------- */ | ||
56 | /* */ | ||
57 | /* Constructor / Destructor */ | ||
58 | /* */ | ||
59 | /* ------------------------------------------------------------------------- */ | ||
60 | |||
61 | /* | ||
62 | Nothing really intesting happens here. | ||
63 | */ | ||
64 | |||
65 | /*! | ||
66 | */ | ||
67 | |||
68 | Vt102Emulation::Vt102Emulation(Widget* gui) : EmulationLayer(gui) | ||
69 | { | ||
70 | QObject::connect(gui,SIGNAL(mouseSignal(int,int,int)), | ||
71 | this,SLOT(onMouse(int,int,int))); | ||
72 | initTokenizer(); | ||
73 | reset(); | ||
74 | } | ||
75 | |||
76 | /*! | ||
77 | */ | ||
78 | |||
79 | Vt102Emulation::~Vt102Emulation() | ||
80 | { | ||
81 | } | ||
82 | |||
83 | /*! | ||
84 | */ | ||
85 | |||
86 | void Vt102Emulation::reset() | ||
87 | { | ||
88 | resetToken(); | ||
89 | resetModes(); | ||
90 | resetCharset(0); screen[0]->reset(); | ||
91 | resetCharset(1); screen[0]->reset(); | ||
92 | setCodec(0); | ||
93 | setKeytrans("linux.keytab"); | ||
94 | } | ||
95 | |||
96 | /* ------------------------------------------------------------------------- */ | ||
97 | /* */ | ||
98 | /* Processing the incoming byte stream */ | ||
99 | /* */ | ||
100 | /* ------------------------------------------------------------------------- */ | ||
101 | |||
102 | /* Incoming Bytes Event pipeline | ||
103 | |||
104 | This section deals with decoding the incoming character stream. | ||
105 | Decoding means here, that the stream is first seperated into `tokens' | ||
106 | which are then mapped to a `meaning' provided as operations by the | ||
107 | `TEScreen' class or by the emulation class itself. | ||
108 | |||
109 | The pipeline proceeds as follows: | ||
110 | |||
111 | - Tokenizing the ESC codes (onRcvChar) | ||
112 | - VT100 code page translation of plain characters (applyCharset) | ||
113 | - Interpretation of ESC codes (tau) | ||
114 | |||
115 | The escape codes and their meaning are described in the | ||
116 | technical reference of this program. | ||
117 | */ | ||
118 | |||
119 | // Tokens ------------------------------------------------------------------ -- | ||
120 | |||
121 | /* | ||
122 | Since the tokens are the central notion if this section, we've put them | ||
123 | in front. They provide the syntactical elements used to represent the | ||
124 | terminals operations as byte sequences. | ||
125 | |||
126 | They are encodes here into a single machine word, so that we can later | ||
127 | switch over them easily. Depending on the token itself, additional | ||
128 | argument variables are filled with parameter values. | ||
129 | |||
130 | The tokens are defined below: | ||
131 | |||
132 | - CHR - Printable characters (32..255 but DEL (=127)) | ||
133 | - CTL - Control characters (0..31 but ESC (= 27), DEL) | ||
134 | - ESC - Escape codes of the form <ESC><CHR but `[]()+*#'> | ||
135 | - ESC_DE - Escape codes of the form <ESC><any of `()+*#%'> C | ||
136 | - CSI_PN - Escape codes of the form <ESC>'[' {Pn} ';' {Pn} C | ||
137 | - CSI_PS - Escape codes of the form <ESC>'[' {Pn} ';' ... C | ||
138 | - CSI_PR - Escape codes of the form <ESC>'[' '?' {Pn} ';' ... C | ||
139 | - VT52 - VT52 escape codes | ||
140 | - <ESC><Chr> | ||
141 | - <ESC>'Y'{Pc}{Pc} | ||
142 | - XTE_HA - Xterm hacks <ESC>`]' {Pn} `;' {Text} <BEL> | ||
143 | note that this is handled differently | ||
144 | |||
145 | The last two forms allow list of arguments. Since the elements of | ||
146 | the lists are treated individually the same way, they are passed | ||
147 | as individual tokens to the interpretation. Further, because the | ||
148 | meaning of the parameters are names (althought represented as numbers), | ||
149 | they are includes within the token ('N'). | ||
150 | |||
151 | */ | ||
152 | |||
153 | #define TY_CONSTR(T,A,N) ( ((((int)N) & 0xffff) << 16) | ((((int)A) & 0xff) << 8) | (((int)T) & 0xff) ) | ||
154 | |||
155 | #define TY_CHR___( ) TY_CONSTR(0,0,0) | ||
156 | #define TY_CTL___(A ) TY_CONSTR(1,A,0) | ||
157 | #define TY_ESC___(A ) TY_CONSTR(2,A,0) | ||
158 | #define TY_ESC_CS(A,B) TY_CONSTR(3,A,B) | ||
159 | #define TY_ESC_DE(A ) TY_CONSTR(4,A,0) | ||
160 | #define TY_CSI_PS(A,N) TY_CONSTR(5,A,N) | ||
161 | #define TY_CSI_PN(A ) TY_CONSTR(6,A,0) | ||
162 | #define TY_CSI_PR(A,N) TY_CONSTR(7,A,N) | ||
163 | |||
164 | #define TY_VT52__(A ) TY_CONSTR(8,A,0) | ||
165 | |||
166 | // Tokenizer --------------------------------------------------------------- -- | ||
167 | |||
168 | /* The tokenizers state | ||
169 | |||
170 | The state is represented by the buffer (pbuf, ppos), | ||
171 | and accompanied by decoded arguments kept in (argv,argc). | ||
172 | Note that they are kept internal in the tokenizer. | ||
173 | */ | ||
174 | |||
175 | void Vt102Emulation::resetToken() | ||
176 | { | ||
177 | ppos = 0; argc = 0; argv[0] = 0; argv[1] = 0; | ||
178 | } | ||
179 | |||
180 | void Vt102Emulation::addDigit(int dig) | ||
181 | { | ||
182 | argv[argc] = 10*argv[argc] + dig; | ||
183 | } | ||
184 | |||
185 | void Vt102Emulation::addArgument() | ||
186 | { | ||
187 | argc = QMIN(argc+1,MAXARGS-1); | ||
188 | argv[argc] = 0; | ||
189 | } | ||
190 | |||
191 | void Vt102Emulation::pushToToken(int cc) | ||
192 | { | ||
193 | pbuf[ppos] = cc; | ||
194 | ppos = QMIN(ppos+1,MAXPBUF-1); | ||
195 | } | ||
196 | |||
197 | // Character Classes used while decoding | ||
198 | |||
199 | #define CTL 1 | ||
200 | #define CHR 2 | ||
201 | #define CPN 4 | ||
202 | #define DIG 8 | ||
203 | #define SCS 16 | ||
204 | #define GRP 32 | ||
205 | |||
206 | void Vt102Emulation::initTokenizer() | ||
207 | { int i; UINT8* s; | ||
208 | for(i = 0; i < 256; i++) tbl[ i] = 0; | ||
209 | for(i = 0; i < 32; i++) tbl[ i] |= CTL; | ||
210 | for(i = 32; i < 256; i++) tbl[ i] |= CHR; | ||
211 | for(s = (UINT8*)"@ABCDGHLMPXcdfry"; *s; s++) tbl[*s] |= CPN; | ||
212 | for(s = (UINT8*)"0123456789" ; *s; s++) tbl[*s] |= DIG; | ||
213 | for(s = (UINT8*)"()+*%" ; *s; s++) tbl[*s] |= SCS; | ||
214 | for(s = (UINT8*)"()+*#[]%" ; *s; s++) tbl[*s] |= GRP; | ||
215 | resetToken(); | ||
216 | } | ||
217 | |||
218 | /* Ok, here comes the nasty part of the decoder. | ||
219 | |||
220 | Instead of keeping an explicit state, we deduce it from the | ||
221 | token scanned so far. It is then immediately combined with | ||
222 | the current character to form a scanning decision. | ||
223 | |||
224 | This is done by the following defines. | ||
225 | |||
226 | - P is the length of the token scanned so far. | ||
227 | - L (often P-1) is the position on which contents we base a decision. | ||
228 | - C is a character or a group of characters (taken from 'tbl'). | ||
229 | |||
230 | Note that they need to applied in proper order. | ||
231 | */ | ||
232 | |||
233 | #define lec(P,L,C) (p == (P) && s[(L)] == (C)) | ||
234 | #define lun( ) (p == 1 && cc >= 32 ) | ||
235 | #define les(P,L,C) (p == (P) && s[L] < 256 && (tbl[s[(L)]] & (C)) == (C)) | ||
236 | #define eec(C) (p >= 3 && cc == (C)) | ||
237 | #define ees(C) (p >= 3 && cc < 256 && (tbl[ cc ] & (C)) == (C)) | ||
238 | #define eps(C) (p >= 3 && s[2] != '?' && cc < 256 && (tbl[ cc ] & (C)) == (C)) | ||
239 | #define epp( ) (p >= 3 && s[2] == '?' ) | ||
240 | #define egt( ) (p == 3 && s[2] == '>' ) | ||
241 | #define Xpe (ppos>=2 && pbuf[1] == ']' ) | ||
242 | #define Xte (Xpe && cc == 7 ) | ||
243 | #define ces(C) ( cc < 256 && (tbl[ cc ] & (C)) == (C) && !Xte) | ||
244 | |||
245 | #define ESC 27 | ||
246 | #define CNTL(c) ((c)-'@') | ||
247 | |||
248 | // process an incoming unicode character | ||
249 | |||
250 | void Vt102Emulation::onRcvChar(int cc) | ||
251 | { int i; | ||
252 | |||
253 | if (cc == 127) return; //VT100: ignore. | ||
254 | |||
255 | if (ces( CTL)) | ||
256 | { // DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100 | ||
257 | // This means, they do neither a resetToken nor a pushToToken. Some of them, do | ||
258 | // of course. Guess this originates from a weakly layered handling of the X-on | ||
259 | // X-off protocol, which comes really below this level. | ||
260 | if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) resetToken(); //VT100: CAN or SUB | ||
261 | if (cc != ESC) { tau( TY_CTL___(cc+'@' ), 0, 0); return; } | ||
262 | } | ||
263 | |||
264 | pushToToken(cc); // advance the state | ||
265 | |||
266 | int* s = pbuf; | ||
267 | int p = ppos; | ||
268 | |||
269 | if (getMode(MODE_Ansi)) // decide on proper action | ||
270 | { | ||
271 | if (lec(1,0,ESC)) { return; } | ||
272 | if (les(2,1,GRP)) { return; } | ||
273 | if (Xte ) { XtermHack(); resetToken(); return; } | ||
274 | if (Xpe ) { return; } | ||
275 | if (lec(3,2,'?')) { return; } | ||
276 | if (lec(3,2,'>')) { return; } | ||
277 | if (lun( )) { tau( TY_CHR___(), applyCharset(cc), 0); resetToken(); return; } | ||
278 | if (lec(2,0,ESC)) { tau( TY_ESC___(s[1]), 0, 0); resetToken(); return; } | ||
279 | if (les(3,1,SCS)) { tau( TY_ESC_CS(s[1],s[2]), 0, 0); resetToken(); return; } | ||
280 | if (lec(3,1,'#')) { tau( TY_ESC_DE(s[2]), 0, 0); resetToken(); return; } | ||
281 | // if (egt( )) { tau( TY_CSI_PG(cc ), '>', 0); resetToken(); return; } | ||
282 | if (eps( CPN)) { tau( TY_CSI_PN(cc), argv[0],argv[1]); resetToken(); return; } | ||
283 | if (ees( DIG)) { addDigit(cc-'0'); return; } | ||
284 | if (eec( ';')) { addArgument(); return; } | ||
285 | for (i=0;i<=argc;i++) | ||
286 | if (epp( )) tau( TY_CSI_PR(cc,argv[i]), 0, 0); else | ||
287 | tau( TY_CSI_PS(cc,argv[i]), 0, 0); | ||
288 | resetToken(); | ||
289 | } | ||
290 | else // mode VT52 | ||
291 | { | ||
292 | if (lec(1,0,ESC)) return; | ||
293 | if (les(1,0,CHR)) { tau( TY_CHR___( ), s[0], 0); resetToken(); return; } | ||
294 | if (lec(2,1,'Y')) return; | ||
295 | if (lec(3,1,'Y')) return; | ||
296 | if (p < 4) { tau( TY_VT52__(s[1] ), 0, 0); resetToken(); return; } | ||
297 | tau( TY_VT52__(s[1] ), s[2],s[3]); resetToken(); return; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | void Vt102Emulation::XtermHack() | ||
302 | { int i,arg = 0; | ||
303 | for (i = 2; i < ppos && '0'<=pbuf[i] && pbuf[i]<'9' ; i++) | ||
304 | arg = 10*arg + (pbuf[i]-'0'); | ||
305 | if (pbuf[i] != ';') { ReportErrorToken(); return; } | ||
306 | QChar *str = new QChar[ppos-i-2]; | ||
307 | for (int j = 0; j < ppos-i-2; j++) str[j] = pbuf[i+1+j]; | ||
308 | QString unistr(str,ppos-i-2); | ||
309 | // arg == 1 doesn't change the title. In XTerm it only changes the icon name | ||
310 | // (btw: arg=0 changes title and icon, arg=1 only icon, arg=2 only title | ||
311 | if (arg == 0 || arg == 2) emit changeTitle(arg,unistr); | ||
312 | delete [] str; | ||
313 | } | ||
314 | |||
315 | // Interpreting Codes --------------------------------------------------------- | ||
316 | |||
317 | /* | ||
318 | Now that the incoming character stream is properly tokenized, | ||
319 | meaning is assigned to them. These are either operations of | ||
320 | the current screen, or of the emulation class itself. | ||
321 | |||
322 | The token to be interpreteted comes in as a machine word | ||
323 | possibly accompanied by two parameters. | ||
324 | |||
325 | Likewise, the operations assigned to, come with up to two | ||
326 | arguments. One could consider to make up a proper table | ||
327 | from the function below. | ||
328 | |||
329 | The technical reference manual provides more informations | ||
330 | about this mapping. | ||
331 | */ | ||
332 | |||
333 | void Vt102Emulation::tau( int token, int p, int q ) | ||
334 | { | ||
335 | //scan_buffer_report(); | ||
336 | //if (token == TY_CHR___()) printf("%c",p); else | ||
337 | //printf("tau(%d,%d,%d, %d,%d)\n",(token>>0)&0xff,(token>>8)&0xff,(token>>16)&0xffff,p,q); | ||
338 | switch (token) | ||
339 | { | ||
340 | |||
341 | case TY_CHR___( ) : scr->ShowCharacter (p ); break; //UTF16 | ||
342 | |||
343 | // 127 DEL : ignored on input | ||
344 | |||
345 | case TY_CTL___('@' ) : /* NUL: ignored */ break; | ||
346 | case TY_CTL___('A' ) : /* SOH: ignored */ break; | ||
347 | case TY_CTL___('B' ) : /* STX: ignored */ break; | ||
348 | case TY_CTL___('C' ) : /* ETX: ignored */ break; | ||
349 | case TY_CTL___('D' ) : /* EOT: ignored */ break; | ||
350 | case TY_CTL___('E' ) : reportAnswerBack ( ); break; //VT100 | ||
351 | case TY_CTL___('F' ) : /* ACK: ignored */ break; | ||
352 | case TY_CTL___('G' ) : gui->Bell ( ); break; //VT100 | ||
353 | case TY_CTL___('H' ) : scr->BackSpace ( ); break; //VT100 | ||
354 | case TY_CTL___('I' ) : scr->Tabulate ( ); break; //VT100 | ||
355 | case TY_CTL___('J' ) : scr->NewLine ( ); break; //VT100 | ||
356 | case TY_CTL___('K' ) : scr->NewLine ( ); break; //VT100 | ||
357 | case TY_CTL___('L' ) : scr->NewLine ( ); break; //VT100 | ||
358 | case TY_CTL___('M' ) : scr->Return ( ); break; //VT100 | ||
359 | |||
360 | case TY_CTL___('N' ) : useCharset ( 1); break; //VT100 | ||
361 | case TY_CTL___('O' ) : useCharset ( 0); break; //VT100 | ||
362 | |||
363 | case TY_CTL___('P' ) : /* DLE: ignored */ break; | ||
364 | case TY_CTL___('Q' ) : /* DC1: XON continue */ break; //VT100 | ||
365 | case TY_CTL___('R' ) : /* DC2: ignored */ break; | ||
366 | case TY_CTL___('S' ) : /* DC3: XOFF halt */ break; //VT100 | ||
367 | case TY_CTL___('T' ) : /* DC4: ignored */ break; | ||
368 | case TY_CTL___('U' ) : /* NAK: ignored */ break; | ||
369 | case TY_CTL___('V' ) : /* SYN: ignored */ break; | ||
370 | case TY_CTL___('W' ) : /* ETB: ignored */ break; | ||
371 | case TY_CTL___('X' ) : scr->ShowCharacter ( 0x2592); break; //VT100 | ||
372 | case TY_CTL___('Y' ) : /* EM : ignored */ break; | ||
373 | case TY_CTL___('Z' ) : scr->ShowCharacter ( 0x2592); break; //VT100 | ||
374 | case TY_CTL___('[' ) : /* ESC: cannot be seen here. */ break; | ||
375 | case TY_CTL___('\\' ) : /* FS : ignored */ break; | ||
376 | case TY_CTL___(']' ) : /* GS : ignored */ break; | ||
377 | case TY_CTL___('^' ) : /* RS : ignored */ break; | ||
378 | case TY_CTL___('_' ) : /* US : ignored */ break; | ||
379 | |||
380 | case TY_ESC___('D' ) : scr->index ( ); break; //VT100 | ||
381 | case TY_ESC___('E' ) : scr->NextLine ( ); break; //VT100 | ||
382 | case TY_ESC___('H' ) : scr->changeTabStop (TRUE ); break; //VT100 | ||
383 | case TY_ESC___('M' ) : scr->reverseIndex ( ); break; //VT100 | ||
384 | case TY_ESC___('Z' ) : reportTerminalType ( ); break; | ||
385 | case TY_ESC___('c' ) : reset ( ); break; | ||
386 | |||
387 | case TY_ESC___('n' ) : useCharset ( 2); break; | ||
388 | case TY_ESC___('o' ) : useCharset ( 3); break; | ||
389 | case TY_ESC___('7' ) : saveCursor ( ); break; | ||
390 | case TY_ESC___('8' ) : restoreCursor ( ); break; | ||
391 | |||
392 | case TY_ESC___('=' ) : setMode (MODE_AppKeyPad); break; | ||
393 | case TY_ESC___('>' ) : resetMode (MODE_AppKeyPad); break; | ||
394 | case TY_ESC___('<' ) : setMode (MODE_Ansi ); break; //VT100 | ||
395 | |||
396 | case TY_ESC_CS('(', '0') : setCharset (0, '0'); break; //VT100 | ||
397 | case TY_ESC_CS('(', 'A') : setCharset (0, 'A'); break; //VT100 | ||
398 | case TY_ESC_CS('(', 'B') : setCharset (0, 'B'); break; //VT100 | ||
399 | |||
400 | case TY_ESC_CS(')', '0') : setCharset (1, '0'); break; //VT100 | ||
401 | case TY_ESC_CS(')', 'A') : setCharset (1, 'A'); break; //VT100 | ||
402 | case TY_ESC_CS(')', 'B') : setCharset (1, 'B'); break; //VT100 | ||
403 | |||
404 | case TY_ESC_CS('*', '0') : setCharset (2, '0'); break; //VT100 | ||
405 | case TY_ESC_CS('*', 'A') : setCharset (2, 'A'); break; //VT100 | ||
406 | case TY_ESC_CS('*', 'B') : setCharset (2, 'B'); break; //VT100 | ||
407 | |||
408 | case TY_ESC_CS('+', '0') : setCharset (3, '0'); break; //VT100 | ||
409 | case TY_ESC_CS('+', 'A') : setCharset (3, 'A'); break; //VT100 | ||
410 | case TY_ESC_CS('+', 'B') : setCharset (3, 'B'); break; //VT100 | ||
411 | |||
412 | case TY_ESC_CS('%', 'G') : setCodec (1 ); break; //LINUX | ||
413 | case TY_ESC_CS('%', '@') : setCodec (0 ); break; //LINUX | ||
414 | |||
415 | case TY_ESC_DE('3' ) : /* IGNORED: double high, top half */ break; | ||
416 | case TY_ESC_DE('4' ) : /* IGNORED: double high, bottom half */ break; | ||
417 | case TY_ESC_DE('5' ) : /* IGNORED: single width, single high*/ break; | ||
418 | case TY_ESC_DE('6' ) : /* IGNORED: double width, single high*/ break; | ||
419 | case TY_ESC_DE('8' ) : scr->helpAlign ( ); break; | ||
420 | |||
421 | case TY_CSI_PS('K', 0) : scr->clearToEndOfLine ( ); break; | ||
422 | case TY_CSI_PS('K', 1) : scr->clearToBeginOfLine ( ); break; | ||
423 | case TY_CSI_PS('K', 2) : scr->clearEntireLine ( ); break; | ||
424 | case TY_CSI_PS('J', 0) : scr->clearToEndOfScreen ( ); break; | ||
425 | case TY_CSI_PS('J', 1) : scr->clearToBeginOfScreen ( ); break; | ||
426 | case TY_CSI_PS('J', 2) : scr->clearEntireScreen ( ); break; | ||
427 | case TY_CSI_PS('g', 0) : scr->changeTabStop (FALSE ); break; //VT100 | ||
428 | case TY_CSI_PS('g', 3) : scr->clearTabStops ( ); break; //VT100 | ||
429 | case TY_CSI_PS('h', 4) : scr-> setMode (MODE_Insert ); break; | ||
430 | case TY_CSI_PS('h', 20) : setMode (MODE_NewLine ); break; | ||
431 | case TY_CSI_PS('i', 0) : /* IGNORE: attached printer */ break; //VT100 | ||
432 | case TY_CSI_PS('l', 4) : scr-> resetMode (MODE_Insert ); break; | ||
433 | case TY_CSI_PS('l', 20) : resetMode (MODE_NewLine ); break; | ||
434 | |||
435 | case TY_CSI_PS('m', 0) : scr->setDefaultRendition ( ); break; | ||
436 | case TY_CSI_PS('m', 1) : scr-> setRendition (RE_BOLD ); break; //VT100 | ||
437 | case TY_CSI_PS('m', 4) : scr-> setRendition (RE_UNDERLINE); break; //VT100 | ||
438 | case TY_CSI_PS('m', 5) : scr-> setRendition (RE_BLINK ); break; //VT100 | ||
439 | case TY_CSI_PS('m', 7) : scr-> setRendition (RE_REVERSE ); break; | ||
440 | case TY_CSI_PS('m', 10) : /* IGNORED: mapping related */ break; //LINUX | ||
441 | case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX | ||
442 | case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX | ||
443 | case TY_CSI_PS('m', 22) : scr->resetRendition (RE_BOLD ); break; | ||
444 | case TY_CSI_PS('m', 24) : scr->resetRendition (RE_UNDERLINE); break; | ||
445 | case TY_CSI_PS('m', 25) : scr->resetRendition (RE_BLINK ); break; | ||
446 | case TY_CSI_PS('m', 27) : scr->resetRendition (RE_REVERSE ); break; | ||
447 | |||
448 | case TY_CSI_PS('m', 30) : scr->setForeColor ( 0); break; | ||
449 | case TY_CSI_PS('m', 31) : scr->setForeColor ( 1); break; | ||
450 | case TY_CSI_PS('m', 32) : scr->setForeColor ( 2); break; | ||
451 | case TY_CSI_PS('m', 33) : scr->setForeColor ( 3); break; | ||
452 | case TY_CSI_PS('m', 34) : scr->setForeColor ( 4); break; | ||
453 | case TY_CSI_PS('m', 35) : scr->setForeColor ( 5); break; | ||
454 | case TY_CSI_PS('m', 36) : scr->setForeColor ( 6); break; | ||
455 | case TY_CSI_PS('m', 37) : scr->setForeColor ( 7); break; | ||
456 | case TY_CSI_PS('m', 39) : scr->setForeColorToDefault( ); break; | ||
457 | |||
458 | case TY_CSI_PS('m', 40) : scr->setBackColor ( 0); break; | ||
459 | case TY_CSI_PS('m', 41) : scr->setBackColor ( 1); break; | ||
460 | case TY_CSI_PS('m', 42) : scr->setBackColor ( 2); break; | ||
461 | case TY_CSI_PS('m', 43) : scr->setBackColor ( 3); break; | ||
462 | case TY_CSI_PS('m', 44) : scr->setBackColor ( 4); break; | ||
463 | case TY_CSI_PS('m', 45) : scr->setBackColor ( 5); break; | ||
464 | case TY_CSI_PS('m', 46) : scr->setBackColor ( 6); break; | ||
465 | case TY_CSI_PS('m', 47) : scr->setBackColor ( 7); break; | ||
466 | case TY_CSI_PS('m', 49) : scr->setBackColorToDefault( ); break; | ||
467 | |||
468 | case TY_CSI_PS('m', 90) : scr->setForeColor ( 8); break; | ||
469 | case TY_CSI_PS('m', 91) : scr->setForeColor ( 9); break; | ||
470 | case TY_CSI_PS('m', 92) : scr->setForeColor ( 10); break; | ||
471 | case TY_CSI_PS('m', 93) : scr->setForeColor ( 11); break; | ||
472 | case TY_CSI_PS('m', 94) : scr->setForeColor ( 12); break; | ||
473 | case TY_CSI_PS('m', 95) : scr->setForeColor ( 13); break; | ||
474 | case TY_CSI_PS('m', 96) : scr->setForeColor ( 14); break; | ||
475 | case TY_CSI_PS('m', 97) : scr->setForeColor ( 15); break; | ||
476 | |||
477 | case TY_CSI_PS('m', 100) : scr->setBackColor ( 8); break; | ||
478 | case TY_CSI_PS('m', 101) : scr->setBackColor ( 9); break; | ||
479 | case TY_CSI_PS('m', 102) : scr->setBackColor ( 10); break; | ||
480 | case TY_CSI_PS('m', 103) : scr->setBackColor ( 11); break; | ||
481 | case TY_CSI_PS('m', 104) : scr->setBackColor ( 12); break; | ||
482 | case TY_CSI_PS('m', 105) : scr->setBackColor ( 13); break; | ||
483 | case TY_CSI_PS('m', 106) : scr->setBackColor ( 14); break; | ||
484 | case TY_CSI_PS('m', 107) : scr->setBackColor ( 15); break; | ||
485 | |||
486 | case TY_CSI_PS('n', 5) : reportStatus ( ); break; | ||
487 | case TY_CSI_PS('n', 6) : reportCursorPosition ( ); break; | ||
488 | case TY_CSI_PS('q', 0) : /* IGNORED: LEDs off */ break; //VT100 | ||
489 | case TY_CSI_PS('q', 1) : /* IGNORED: LED1 on */ break; //VT100 | ||
490 | case TY_CSI_PS('q', 2) : /* IGNORED: LED2 on */ break; //VT100 | ||
491 | case TY_CSI_PS('q', 3) : /* IGNORED: LED3 on */ break; //VT100 | ||
492 | case TY_CSI_PS('q', 4) : /* IGNORED: LED4 on */ break; //VT100 | ||
493 | case TY_CSI_PS('x', 0) : reportTerminalParms ( 2); break; //VT100 | ||
494 | case TY_CSI_PS('x', 1) : reportTerminalParms ( 3); break; //VT100 | ||
495 | |||
496 | case TY_CSI_PN('@' ) : scr->insertChars (p ); break; | ||
497 | case TY_CSI_PN('A' ) : scr->cursorUp (p ); break; //VT100 | ||
498 | case TY_CSI_PN('B' ) : scr->cursorDown (p ); break; //VT100 | ||
499 | case TY_CSI_PN('C' ) : scr->cursorRight (p ); break; //VT100 | ||
500 | case TY_CSI_PN('D' ) : scr->cursorLeft (p ); break; //VT100 | ||
501 | case TY_CSI_PN('G' ) : scr->setCursorX (p ); break; //LINUX | ||
502 | case TY_CSI_PN('H' ) : scr->setCursorYX (p, q); break; //VT100 | ||
503 | case TY_CSI_PN('L' ) : scr->insertLines (p ); break; | ||
504 | case TY_CSI_PN('M' ) : scr->deleteLines (p ); break; | ||
505 | case TY_CSI_PN('P' ) : scr->deleteChars (p ); break; | ||
506 | case TY_CSI_PN('X' ) : scr->eraseChars (p ); break; | ||
507 | case TY_CSI_PN('c' ) : reportTerminalType ( ); break; //VT100 | ||
508 | case TY_CSI_PN('d' ) : scr->setCursorY (p ); break; //LINUX | ||
509 | case TY_CSI_PN('f' ) : scr->setCursorYX (p, q); break; //VT100 | ||
510 | case TY_CSI_PN('r' ) : scr->setMargins (p, q); break; //VT100 | ||
511 | case TY_CSI_PN('y' ) : /* IGNORED: Confidence test */ break; //VT100 | ||
512 | |||
513 | case TY_CSI_PR('h', 1) : setMode (MODE_AppCuKeys); break; //VT100 | ||
514 | case TY_CSI_PR('l', 1) : resetMode (MODE_AppCuKeys); break; //VT100 | ||
515 | case TY_CSI_PR('s', 1) : saveMode (MODE_AppCuKeys); break; //FIXME | ||
516 | case TY_CSI_PR('r', 1) : restoreMode (MODE_AppCuKeys); break; //FIXME | ||
517 | |||
518 | case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100 | ||
519 | |||
520 | case TY_CSI_PR('h', 3) : setColumns ( 132); break; //VT100 | ||
521 | case TY_CSI_PR('l', 3) : setColumns ( 80); break; //VT100 | ||
522 | |||
523 | case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100 | ||
524 | case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100 | ||
525 | |||
526 | case TY_CSI_PR('h', 5) : scr-> setMode (MODE_Screen ); break; //VT100 | ||
527 | case TY_CSI_PR('l', 5) : scr-> resetMode (MODE_Screen ); break; //VT100 | ||
528 | |||
529 | case TY_CSI_PR('h', 6) : scr-> setMode (MODE_Origin ); break; //VT100 | ||
530 | case TY_CSI_PR('l', 6) : scr-> resetMode (MODE_Origin ); break; //VT100 | ||
531 | case TY_CSI_PR('s', 6) : scr-> saveMode (MODE_Origin ); break; //FIXME | ||
532 | case TY_CSI_PR('r', 6) : scr->restoreMode (MODE_Origin ); break; //FIXME | ||
533 | |||
534 | case TY_CSI_PR('h', 7) : scr-> setMode (MODE_Wrap ); break; //VT100 | ||
535 | case TY_CSI_PR('l', 7) : scr-> resetMode (MODE_Wrap ); break; //VT100 | ||
536 | case TY_CSI_PR('s', 7) : scr-> saveMode (MODE_Wrap ); break; //FIXME | ||
537 | case TY_CSI_PR('r', 7) : scr->restoreMode (MODE_Wrap ); break; //FIXME | ||
538 | |||
539 | case TY_CSI_PR('h', 8) : /* IGNORED: autorepeat on */ break; //VT100 | ||
540 | case TY_CSI_PR('l', 8) : /* IGNORED: autorepeat off */ break; //VT100 | ||
541 | |||
542 | case TY_CSI_PR('h', 9) : /* IGNORED: interlace */ break; //VT100 | ||
543 | case TY_CSI_PR('l', 9) : /* IGNORED: interlace */ break; //VT100 | ||
544 | |||
545 | case TY_CSI_PR('h', 25) : setMode (MODE_Cursor ); break; //VT100 | ||
546 | case TY_CSI_PR('l', 25) : resetMode (MODE_Cursor ); break; //VT100 | ||
547 | |||
548 | case TY_CSI_PR('h', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM | ||
549 | case TY_CSI_PR('l', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM | ||
550 | case TY_CSI_PR('s', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM | ||
551 | case TY_CSI_PR('r', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM | ||
552 | |||
553 | case TY_CSI_PR('h', 47) : setMode (MODE_AppScreen); break; //VT100 | ||
554 | case TY_CSI_PR('l', 47) : resetMode (MODE_AppScreen); break; //VT100 | ||
555 | |||
556 | case TY_CSI_PR('h', 1000) : setMode (MODE_Mouse1000); break; //XTERM | ||
557 | case TY_CSI_PR('l', 1000) : resetMode (MODE_Mouse1000); break; //XTERM | ||
558 | case TY_CSI_PR('s', 1000) : saveMode (MODE_Mouse1000); break; //XTERM | ||
559 | case TY_CSI_PR('r', 1000) : restoreMode (MODE_Mouse1000); break; //XTERM | ||
560 | |||
561 | case TY_CSI_PR('h', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM | ||
562 | case TY_CSI_PR('l', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM | ||
563 | case TY_CSI_PR('s', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM | ||
564 | case TY_CSI_PR('r', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM | ||
565 | |||
566 | case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM | ||
567 | case TY_CSI_PR('l', 1047) : resetMode (MODE_AppScreen); break; //XTERM | ||
568 | |||
569 | //FIXME: Unitoken: save translations | ||
570 | case TY_CSI_PR('h', 1048) : saveCursor ( ); break; //XTERM | ||
571 | case TY_CSI_PR('l', 1048) : restoreCursor ( ); break; //XTERM | ||
572 | |||
573 | //FIXME: every once new sequences like this pop up in xterm. | ||
574 | // Here's a guess of what they could mean. | ||
575 | case TY_CSI_PR('h', 1049) : setMode (MODE_AppScreen); break; //XTERM | ||
576 | case TY_CSI_PR('l', 1049) : resetMode (MODE_AppScreen); break; //XTERM | ||
577 | |||
578 | //FIXME: when changing between vt52 and ansi mode evtl do some resetting. | ||
579 | case TY_VT52__('A' ) : scr->cursorUp ( 1); break; //VT52 | ||
580 | case TY_VT52__('B' ) : scr->cursorDown ( 1); break; //VT52 | ||
581 | case TY_VT52__('C' ) : scr->cursorRight ( 1); break; //VT52 | ||
582 | case TY_VT52__('D' ) : scr->cursorLeft ( 1); break; //VT52 | ||
583 | |||
584 | case TY_VT52__('F' ) : setAndUseCharset (0, '0'); break; //VT52 | ||
585 | case TY_VT52__('G' ) : setAndUseCharset (0, 'B'); break; //VT52 | ||
586 | |||
587 | case TY_VT52__('H' ) : scr->setCursorYX (1,1 ); break; //VT52 | ||
588 | case TY_VT52__('I' ) : scr->reverseIndex ( ); break; //VT52 | ||
589 | case TY_VT52__('J' ) : scr->clearToEndOfScreen ( ); break; //VT52 | ||
590 | case TY_VT52__('K' ) : scr->clearToEndOfLine ( ); break; //VT52 | ||
591 | case TY_VT52__('Y' ) : scr->setCursorYX (p-31,q-31 ); break; //VT52 | ||
592 | case TY_VT52__('Z' ) : reportTerminalType ( ); break; //VT52 | ||
593 | case TY_VT52__('<' ) : setMode (MODE_Ansi ); break; //VT52 | ||
594 | case TY_VT52__('=' ) : setMode (MODE_AppKeyPad); break; //VT52 | ||
595 | case TY_VT52__('>' ) : resetMode (MODE_AppKeyPad); break; //VT52 | ||
596 | |||
597 | default : ReportErrorToken(); break; | ||
598 | }; | ||
599 | } | ||
600 | |||
601 | /* ------------------------------------------------------------------------- */ | ||
602 | /* */ | ||
603 | /* Terminal to Host protocol */ | ||
604 | /* */ | ||
605 | /* ------------------------------------------------------------------------- */ | ||
606 | |||
607 | /* | ||
608 | Outgoing bytes originate from several sources: | ||
609 | |||
610 | - Replies to Enquieries. | ||
611 | - Mouse Events | ||
612 | - Keyboard Events | ||
613 | */ | ||
614 | |||
615 | /*! | ||
616 | */ | ||
617 | |||
618 | void Vt102Emulation::sendString(const char* s) | ||
619 | { | ||
620 | QByteArray tmp; | ||
621 | tmp.setRawData( s, strlen( s )); | ||
622 | emit sndBlock( tmp); | ||
623 | } | ||
624 | |||
625 | void Vt102Emulation::sendString(const QByteArray s) | ||
626 | { | ||
627 | emit sndBlock( s ); | ||
628 | } | ||
629 | |||
630 | // Replies ----------------------------------------------------------------- -- | ||
631 | |||
632 | // This section copes with replies send as response to an enquiery control code. | ||
633 | |||
634 | /*! | ||
635 | */ | ||
636 | |||
637 | void Vt102Emulation::reportCursorPosition() | ||
638 | { char tmp[20]; | ||
639 | sprintf(tmp,"\033[%d;%dR",scr->getCursorY()+1,scr->getCursorX()+1); | ||
640 | sendString(tmp); | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | What follows here is rather obsolete and faked stuff. | ||
645 | The correspondent enquieries are neverthenless issued. | ||
646 | */ | ||
647 | |||
648 | /*! | ||
649 | */ | ||
650 | |||
651 | void Vt102Emulation::reportTerminalType() | ||
652 | { | ||
653 | //FIXME: should change? | ||
654 | if (getMode(MODE_Ansi)) | ||
655 | // sendString("\033[?1;2c"); // I'm a VT100 with AP0 //FIXME: send only in response to ^[[0c | ||
656 | sendString("\033[>0;115;0c"); // I'm a VT220 //FIXME: send only in response to ^[[>c | ||
657 | else | ||
658 | sendString("\033/Z"); // I'm a VT52 | ||
659 | } | ||
660 | |||
661 | void Vt102Emulation::reportTerminalParms(int p) | ||
662 | // DECREPTPARM | ||
663 | { char tmp[100]; | ||
664 | sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true. | ||
665 | sendString(tmp); | ||
666 | } | ||
667 | |||
668 | /*! | ||
669 | */ | ||
670 | |||
671 | void Vt102Emulation::reportStatus() | ||
672 | { | ||
673 | sendString("\033[0n"); //VT100. Device status report. 0 = Ready. | ||
674 | } | ||
675 | |||
676 | /*! | ||
677 | */ | ||
678 | |||
679 | #define ANSWER_BACK "" // This is really obsolete VT100 stuff. | ||
680 | |||
681 | void Vt102Emulation::reportAnswerBack() | ||
682 | { | ||
683 | sendString(ANSWER_BACK); | ||
684 | } | ||
685 | |||
686 | // Mouse Handling ---------------------------------------------------------- -- | ||
687 | |||
688 | /*! | ||
689 | Mouse clicks are possibly reported to the client | ||
690 | application if it has issued interest in them. | ||
691 | They are normally consumed by the widget for copy | ||
692 | and paste, but may be propagated from the widget | ||
693 | when gui->setMouseMarks is set via setMode(MODE_Mouse1000). | ||
694 | |||
695 | `x',`y' are 1-based. | ||
696 | `ev' (event) indicates the button pressed (0-2) | ||
697 | or a general mouse release (3). | ||
698 | */ | ||
699 | |||
700 | void Vt102Emulation::onMouse( int cb, int cx, int cy ) | ||
701 | { char tmp[20]; | ||
702 | if (!connected) return; | ||
703 | sprintf(tmp,"\033[M%c%c%c",cb+040,cx+040,cy+040); | ||
704 | sendString(tmp); | ||
705 | } | ||
706 | |||
707 | // Keyboard Handling ------------------------------------------------------- -- | ||
708 | |||
709 | #define encodeMode(M,B) BITS(B,getMode(M)) | ||
710 | #define encodeStat(M,B) BITS(B,((ev->state() & (M)) == (M))) | ||
711 | |||
712 | /* | ||
713 | Keyboard event handling has been simplified somewhat by pushing | ||
714 | the complications towards a configuration file [see KeyTrans class]. | ||
715 | */ | ||
716 | |||
717 | void Vt102Emulation::onKeyPress( QKeyEvent* ev ) | ||
718 | { | ||
719 | if (!connected) return; // someone else gets the keys | ||
720 | |||
721 | //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); | ||
722 | |||
723 | // revert to non-history when typing | ||
724 | if (scr->getHistCursor() != scr->getHistLines()); | ||
725 | scr->setHistCursor(scr->getHistLines()); | ||
726 | |||
727 | // lookup in keyboard translation table ... | ||
728 | int cmd; const char* txt; int len; | ||
729 | if (keytrans->findEntry(ev->key(), encodeMode(MODE_NewLine , BITS_NewLine ) + // OLD, | ||
730 | encodeMode(MODE_Ansi , BITS_Ansi ) + // OBSOLETE, | ||
731 | encodeMode(MODE_AppCuKeys, BITS_AppCuKeys ) + // VT100 stuff | ||
732 | encodeStat(ControlButton , BITS_Control ) + | ||
733 | encodeStat(ShiftButton , BITS_Shift ) + | ||
734 | encodeStat(AltButton , BITS_Alt ), | ||
735 | &cmd, &txt, &len )) | ||
736 | //printf("cmd: %d, %s, %d\n",cmd,txt,len); | ||
737 | { | ||
738 | switch(cmd) // ... and execute if found. | ||
739 | { | ||
740 | case CMD_emitSelection : gui->emitSelection(); return; | ||
741 | case CMD_scrollPageUp : gui->doScroll(-gui->Lines()/2); return; | ||
742 | case CMD_scrollPageDown : gui->doScroll(+gui->Lines()/2); return; | ||
743 | case CMD_scrollLineUp : gui->doScroll(-1 ); return; | ||
744 | case CMD_scrollLineDown : gui->doScroll(+1 ); return; | ||
745 | case CMD_send : sendString( txt ); return; | ||
746 | case CMD_prevSession : emit prevSession(); return; | ||
747 | case CMD_nextSession : emit nextSession(); return; | ||
748 | } | ||
749 | } | ||
750 | // fall back handling | ||
751 | if (!ev->text().isEmpty()) | ||
752 | { | ||
753 | if (ev->state() & AltButton) sendString("\033"); // ESC, this is the ALT prefix | ||
754 | /// very hacky | ||
755 | if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='A')) sendString("\01"); | ||
756 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='B')) sendString("\02"); | ||
757 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='C')) sendString("\03"); | ||
758 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='D')) sendString("\04"); | ||
759 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='E')) sendString("\05"); | ||
760 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='F')) sendString("\06"); | ||
761 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='G')) sendString("\07"); | ||
762 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='H')) sendString("\010"); | ||
763 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='I')) sendString("\011"); | ||
764 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='J')) sendString("\012"); | ||
765 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='K')) sendString("\013"); | ||
766 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='L')) sendString("\014"); | ||
767 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='M')) sendString("\015"); | ||
768 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='N')) sendString("\016"); | ||
769 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='O')) sendString("\017"); | ||
770 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='P')) sendString("\020"); | ||
771 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='Q')) sendString("\021"); | ||
772 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='R')) sendString("\022"); | ||
773 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='S')) sendString("\023"); | ||
774 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='T')) sendString("\024"); | ||
775 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='U')) sendString("\025"); | ||
776 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='V')) sendString("\026"); | ||
777 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='W')) sendString("\027"); | ||
778 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='X')) sendString("\030"); | ||
779 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='Y')) sendString("\031"); | ||
780 | else if ((ev->state() & ControlButton) && (ev->text().upper().ascii()[0]=='Z')) sendString("\032"); | ||
781 | else | ||
782 | { | ||
783 | QCString s = codec->fromUnicode(ev->text()); // encode for application | ||
784 | sendString( s ); // we may well have s.length() > 1 | ||
785 | } | ||
786 | return; | ||
787 | } | ||
788 | } | ||
789 | |||
790 | /* ------------------------------------------------------------------------- */ | ||
791 | /* */ | ||
792 | /* VT100 Charsets */ | ||
793 | /* */ | ||
794 | /* ------------------------------------------------------------------------- */ | ||
795 | |||
796 | // Character Set Conversion ------------------------------------------------ -- | ||
797 | |||
798 | /* | ||
799 | The processing contains a VT100 specific code translation layer. | ||
800 | It's still in use and mainly responsible for the line drawing graphics. | ||
801 | |||
802 | These and some other glyphs are assigned to codes (0x5f-0xfe) | ||
803 | normally occupied by the latin letters. Since this codes also | ||
804 | appear within control sequences, the extra code conversion | ||
805 | does not permute with the tokenizer and is placed behind it | ||
806 | in the pipeline. It only applies to tokens, which represent | ||
807 | plain characters. | ||
808 | |||
809 | This conversion it eventually continued in TEWidget.C, since | ||
810 | it might involve VT100 enhanced fonts, which have these | ||
811 | particular glyphs allocated in (0x00-0x1f) in their code page. | ||
812 | */ | ||
813 | |||
814 | #define CHARSET charset[scr==screen[1]] | ||
815 | |||
816 | // Apply current character map. | ||
817 | |||
818 | unsigned short Vt102Emulation::applyCharset(unsigned short c) | ||
819 | { | ||
820 | if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c-0x5f]; | ||
821 | if (CHARSET.pound && c == '#' ) return 0xa3; //This mode is obsolete | ||
822 | return c; | ||
823 | } | ||
824 | |||
825 | /* | ||
826 | "Charset" related part of the emulation state. | ||
827 | This configures the VT100 charset filter. | ||
828 | |||
829 | While most operation work on the current screen, | ||
830 | the following two are different. | ||
831 | */ | ||
832 | |||
833 | void Vt102Emulation::resetCharset(int scrno) | ||
834 | { | ||
835 | charset[scrno].cu_cs = 0; | ||
836 | strncpy(charset[scrno].charset,"BBBB",4); | ||
837 | charset[scrno].sa_graphic = FALSE; | ||
838 | charset[scrno].sa_pound = FALSE; | ||
839 | charset[scrno].graphic = FALSE; | ||
840 | charset[scrno].pound = FALSE; | ||
841 | } | ||
842 | |||
843 | /*! | ||
844 | */ | ||
845 | |||
846 | void Vt102Emulation::setCharset(int n, int cs) // on both screens. | ||
847 | { | ||
848 | charset[0].charset[n&3] = cs; useCharset(charset[0].cu_cs); | ||
849 | charset[1].charset[n&3] = cs; useCharset(charset[1].cu_cs); | ||
850 | } | ||
851 | |||
852 | /*! | ||
853 | */ | ||
854 | |||
855 | void Vt102Emulation::setAndUseCharset(int n, int cs) | ||
856 | { | ||
857 | CHARSET.charset[n&3] = cs; | ||
858 | useCharset(n&3); | ||
859 | } | ||
860 | |||
861 | /*! | ||
862 | */ | ||
863 | |||
864 | void Vt102Emulation::useCharset(int n) | ||
865 | { | ||
866 | CHARSET.cu_cs = n&3; | ||
867 | CHARSET.graphic = (CHARSET.charset[n&3] == '0'); | ||
868 | CHARSET.pound = (CHARSET.charset[n&3] == 'A'); //This mode is obsolete | ||
869 | } | ||
870 | |||
871 | /*! Save the cursor position and the rendition attribute settings. */ | ||
872 | |||
873 | void Vt102Emulation::saveCursor() | ||
874 | { | ||
875 | CHARSET.sa_graphic = CHARSET.graphic; | ||
876 | CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete | ||
877 | // we are not clear about these | ||
878 | //sa_charset = charsets[cScreen->charset]; | ||
879 | //sa_charset_num = cScreen->charset; | ||
880 | scr->saveCursor(); | ||
881 | } | ||
882 | |||
883 | /*! Restore the cursor position and the rendition attribute settings. */ | ||
884 | |||
885 | void Vt102Emulation::restoreCursor() | ||
886 | { | ||
887 | CHARSET.graphic = CHARSET.sa_graphic; | ||
888 | CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete | ||
889 | scr->restoreCursor(); | ||
890 | } | ||
891 | |||
892 | /* ------------------------------------------------------------------------- */ | ||
893 | /* */ | ||
894 | /* Mode Operations */ | ||
895 | /* */ | ||
896 | /* ------------------------------------------------------------------------- */ | ||
897 | |||
898 | /* | ||
899 | Some of the emulations state is either added to the state of the screens. | ||
900 | |||
901 | This causes some scoping problems, since different emulations choose to | ||
902 | located the mode either to the current screen or to both. | ||
903 | |||
904 | For strange reasons, the extend of the rendition attributes ranges over | ||
905 | all screens and not over the actual screen. | ||
906 | |||
907 | We decided on the precise precise extend, somehow. | ||
908 | */ | ||
909 | |||
910 | // "Mode" related part of the state. These are all booleans. | ||
911 | |||
912 | void Vt102Emulation::resetModes() | ||
913 | { | ||
914 | resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000); | ||
915 | resetMode(MODE_AppScreen); saveMode(MODE_AppScreen); | ||
916 | // here come obsolete modes | ||
917 | resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys); | ||
918 | resetMode(MODE_NewLine ); | ||
919 | setMode(MODE_Ansi ); | ||
920 | } | ||
921 | |||
922 | void Vt102Emulation::setMode(int m) | ||
923 | { | ||
924 | currParm.mode[m] = TRUE; | ||
925 | switch (m) | ||
926 | { | ||
927 | case MODE_Mouse1000 : gui->setMouseMarks(FALSE); | ||
928 | break; | ||
929 | case MODE_AppScreen : screen[1]->clearSelection(); | ||
930 | screen[1]->clearEntireScreen(); | ||
931 | setScreen(1); | ||
932 | break; | ||
933 | } | ||
934 | if (m < MODES_SCREEN || m == MODE_NewLine) | ||
935 | { | ||
936 | screen[0]->setMode(m); | ||
937 | screen[1]->setMode(m); | ||
938 | } | ||
939 | } | ||
940 | |||
941 | void Vt102Emulation::resetMode(int m) | ||
942 | { | ||
943 | currParm.mode[m] = FALSE; | ||
944 | switch (m) | ||
945 | { | ||
946 | case MODE_Mouse1000 : gui->setMouseMarks(TRUE); | ||
947 | break; | ||
948 | case MODE_AppScreen : screen[0]->clearSelection(); | ||
949 | setScreen(0); | ||
950 | break; | ||
951 | } | ||
952 | if (m < MODES_SCREEN || m == MODE_NewLine) | ||
953 | { | ||
954 | screen[0]->resetMode(m); | ||
955 | screen[1]->resetMode(m); | ||
956 | } | ||
957 | } | ||
958 | |||
959 | void Vt102Emulation::saveMode(int m) | ||
960 | { | ||
961 | saveParm.mode[m] = currParm.mode[m]; | ||
962 | } | ||
963 | |||
964 | void Vt102Emulation::restoreMode(int m) | ||
965 | { | ||
966 | if(saveParm.mode[m]) setMode(m); else resetMode(m); | ||
967 | } | ||
968 | |||
969 | BOOL Vt102Emulation::getMode(int m) | ||
970 | { | ||
971 | return currParm.mode[m]; | ||
972 | } | ||
973 | |||
974 | void Vt102Emulation::setConnect(bool c) | ||
975 | { | ||
976 | EmulationLayer::setConnect(c); | ||
977 | if (c) | ||
978 | { // refresh mouse mode | ||
979 | if (getMode(MODE_Mouse1000)) | ||
980 | setMode(MODE_Mouse1000); | ||
981 | else | ||
982 | resetMode(MODE_Mouse1000); | ||
983 | } | ||
984 | } | ||
985 | |||
986 | /* ------------------------------------------------------------------------- */ | ||
987 | /* */ | ||
988 | /* Diagnostic */ | ||
989 | /* */ | ||
990 | /* ------------------------------------------------------------------------- */ | ||
991 | |||
992 | /*! shows the contents of the scan buffer. | ||
993 | |||
994 | This functions is used for diagnostics. It is called by \e ReportErrorToken | ||
995 | to inform about strings that cannot be decoded or handled by the emulation. | ||
996 | |||
997 | \sa ReportErrorToken | ||
998 | */ | ||
999 | |||
1000 | /*! | ||
1001 | */ | ||
1002 | |||
1003 | static void hexdump(int* s, int len) | ||
1004 | { int i; | ||
1005 | for (i = 0; i < len; i++) | ||
1006 | { | ||
1007 | if (s[i] == '\\') | ||
1008 | printf("\\\\"); | ||
1009 | else | ||
1010 | if ((s[i]) > 32 && s[i] < 127) | ||
1011 | printf("%c",s[i]); | ||
1012 | else | ||
1013 | printf("\\%04x(hex)",s[i]); | ||
1014 | } | ||
1015 | } | ||
1016 | |||
1017 | void Vt102Emulation::scan_buffer_report() | ||
1018 | { | ||
1019 | if (ppos == 0 || ppos == 1 && (pbuf[0] & 0xff) >= 32) return; | ||
1020 | printf("token: "); hexdump(pbuf,ppos); printf("\n"); | ||
1021 | } | ||
1022 | |||
1023 | /*! | ||
1024 | */ | ||
1025 | |||
1026 | void Vt102Emulation::ReportErrorToken() | ||
1027 | { | ||
1028 | printf("undecodable "); scan_buffer_report(); | ||
1029 | } | ||
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 @@ | |||
1 | /* -------------------------------------------------------------------------- */ | ||
2 | /* */ | ||
3 | /* [TEmuVt102.h] X Terminal Emulation */ | ||
4 | /* */ | ||
5 | /* -------------------------------------------------------------------------- */ | ||
6 | /* */ | ||
7 | /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ | ||
8 | /* */ | ||
9 | /* This file is part of Konsole - an X terminal for KDE */ | ||
10 | /* */ | ||
11 | /* -------------------------------------------------------------------------- */ | ||
12 | /* */ | ||
13 | /* Ported Konsole to Qt/Embedded */ | ||
14 | /* */ | ||
15 | /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ | ||
16 | /* */ | ||
17 | /* -------------------------------------------------------------------------- */ | ||
18 | /* Ported embedded-konsole to opie-terminal */ | ||
19 | /* */ | ||
20 | /* Copyright (C) 2002 by opie developers <opie@handhelds.org> */ | ||
21 | /* */ | ||
22 | /* -------------------------------------------------------------------------- */ | ||
23 | |||
24 | #ifndef VT102EMU_H | ||
25 | #define VT102EMU_H | ||
26 | |||
27 | #include "widget.h" | ||
28 | #include "screen.h" | ||
29 | #include "emulation_layer.h" | ||
30 | #include <qtimer.h> | ||
31 | #include <stdio.h> | ||
32 | |||
33 | // | ||
34 | |||
35 | #define MODE_AppScreen (MODES_SCREEN+0) | ||
36 | #define MODE_AppCuKeys (MODES_SCREEN+1) | ||
37 | #define MODE_AppKeyPad (MODES_SCREEN+2) | ||
38 | #define MODE_Mouse1000 (MODES_SCREEN+3) | ||
39 | #define MODE_Ansi (MODES_SCREEN+4) | ||
40 | #define MODE_total (MODES_SCREEN+5) | ||
41 | |||
42 | struct DECpar | ||
43 | { | ||
44 | BOOL mode[MODE_total]; | ||
45 | }; | ||
46 | |||
47 | struct CharCodes | ||
48 | { | ||
49 | // coding info | ||
50 | char charset[4]; // | ||
51 | int cu_cs; // actual charset. | ||
52 | bool graphic; // Some VT100 tricks | ||
53 | bool pound ; // Some VT100 tricks | ||
54 | bool sa_graphic; // saved graphic | ||
55 | bool sa_pound; // saved pound | ||
56 | }; | ||
57 | |||
58 | class Vt102Emulation: public EmulationLayer | ||
59 | { Q_OBJECT | ||
60 | |||
61 | public: | ||
62 | |||
63 | Vt102Emulation(Widget* gui); | ||
64 | ~Vt102Emulation(); | ||
65 | |||
66 | public slots: // signals incoming from Widget | ||
67 | |||
68 | void onKeyPress(QKeyEvent*); | ||
69 | void onMouse(int cb, int cx, int cy); | ||
70 | |||
71 | signals: | ||
72 | |||
73 | void changeTitle(int,const QString&); | ||
74 | void prevSession(); | ||
75 | void nextSession(); | ||
76 | |||
77 | public: | ||
78 | |||
79 | void reset(); | ||
80 | |||
81 | /** | ||
82 | * receive a char from IOLayer | ||
83 | */ | ||
84 | void onRcvChar(int cc); | ||
85 | |||
86 | /** | ||
87 | * sends a list of bytes to the IOLayer | ||
88 | */ | ||
89 | void sendString(const QByteArray); | ||
90 | |||
91 | /** | ||
92 | * @deprecated use QByteArray instead | ||
93 | * see sendString() above | ||
94 | */ | ||
95 | void sendString(const char *); | ||
96 | |||
97 | public: | ||
98 | |||
99 | BOOL getMode (int m); | ||
100 | |||
101 | void setMode (int m); | ||
102 | void resetMode (int m); | ||
103 | void saveMode (int m); | ||
104 | void restoreMode(int m); | ||
105 | void resetModes(); | ||
106 | |||
107 | void setConnect(bool r); | ||
108 | |||
109 | private: | ||
110 | |||
111 | void resetToken(); | ||
112 | #define MAXPBUF 80 | ||
113 | void pushToToken(int cc); | ||
114 | int pbuf[MAXPBUF]; //FIXME: overflow? | ||
115 | int ppos; | ||
116 | #define MAXARGS 15 | ||
117 | void addDigit(int dig); | ||
118 | void addArgument(); | ||
119 | int argv[MAXARGS]; | ||
120 | int argc; | ||
121 | void initTokenizer(); | ||
122 | int tbl[256]; | ||
123 | |||
124 | void scan_buffer_report(); //FIXME: rename | ||
125 | void ReportErrorToken(); //FIXME: rename | ||
126 | |||
127 | void tau(int code, int p, int q); | ||
128 | void XtermHack(); | ||
129 | |||
130 | // | ||
131 | |||
132 | void reportTerminalType(); | ||
133 | void reportStatus(); | ||
134 | void reportAnswerBack(); | ||
135 | void reportCursorPosition(); | ||
136 | void reportTerminalParms(int p); | ||
137 | |||
138 | protected: | ||
139 | |||
140 | unsigned short applyCharset(unsigned short c); | ||
141 | void setCharset(int n, int cs); | ||
142 | void useCharset(int n); | ||
143 | void setAndUseCharset(int n, int cs); | ||
144 | void saveCursor(); | ||
145 | void restoreCursor(); | ||
146 | void resetCharset(int scrno); | ||
147 | CharCodes charset[2]; | ||
148 | |||
149 | DECpar currParm; | ||
150 | DECpar saveParm; | ||
151 | }; | ||
152 | |||
153 | #endif // ifndef ANSIEMU_H | ||
diff --git a/noncore/apps/opie-console/vt102emulation.o b/noncore/apps/opie-console/vt102emulation.o new file mode 100644 index 0000000..009a4fa --- a/dev/null +++ b/noncore/apps/opie-console/vt102emulation.o | |||
Binary files differ | |||