1 /*    con_slang.cpp
2  *
3  *    Copyright (c) 1998, Istv�n V�radi
4  *    Copyright (c) 2010, Zdenek Kabelac
5  *
6  *    You may distribute under the terms of either the GNU General Public
7  *    License or the Artistic License, as specified in the README file.
8  *
9  */
10 
11 // to have %PRId64 defined for C++
12 #define __STDC_FORMAT_MACROS
13 
14 #include "c_config.h"
15 #include "con_tty.h"
16 #include "console.h"
17 #include "gui.h"
18 #include "s_string.h"
19 #include "sysdep.h"
20 //#include "slangkbd.h"
21 
22 //#include <slang/slang.h>
23 #include <slang.h>
24 
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sys/time.h>
30 #include <sys/wait.h>
31 #include <unistd.h>
32 
33 extern TEvent NextEvent; // g_text.cpp
34 
35 /* These characters cannot appear on a console, so we can detect
36  * them in the output routine.
37  */
38 #define DCH_SLANG_C1         128
39 #define DCH_SLANG_C2         129
40 #define DCH_SLANG_C3         130
41 #define DCH_SLANG_C4         131
42 #define DCH_SLANG_H          132
43 #define DCH_SLANG_V          133
44 #define DCH_SLANG_M1         134
45 #define DCH_SLANG_M2         135
46 #define DCH_SLANG_M3         136
47 #define DCH_SLANG_M4         137
48 #define DCH_SLANG_X          138
49 #define DCH_SLANG_RPTR       139
50 #define DCH_SLANG_EOL        140
51 #define DCH_SLANG_EOF        141
52 #define DCH_SLANG_END        142
53 #define DCH_SLANG_AUP        143
54 #define DCH_SLANG_ADOWN      144
55 #define DCH_SLANG_HFORE      145
56 #define DCH_SLANG_HBACK      146
57 #define DCH_SLANG_ALEFT      147
58 #define DCH_SLANG_ARIGHT     148
59 
60 // i  VT
61 // }  pound
62 // {  PI
63 static const char slang_dchs[] =
64 {
65     'l',
66     'k',
67     'm',
68     'j',
69     'q',
70     'x',
71     'w',
72     't',
73     'u',
74     'f',
75     'v',
76     'n',
77     '~',
78     '`',
79     'q',
80     '-',
81     '.',
82     ' ',
83     'a',
84     ',',
85     '+'
86 };
87 
88 static SLsmg_Char_Type raw_dchs[sizeof(slang_dchs)];
89 
ftesl_get_dch(SLsmg_Char_Type raw)90 static unsigned char ftesl_get_dch(SLsmg_Char_Type raw)
91 {
92     for (size_t i = 0; i < sizeof(slang_dchs); i++)
93 	if (raw_dchs[i].nchars == raw.nchars
94 	    && !memcmp(raw_dchs[i].wchars, raw.wchars,
95 		       raw.nchars * sizeof(*raw.wchars)))
96 	    return (unsigned char)(DCH_SLANG_C1 + i);
97     return DCH_SLANG_EOL;
98 }
99 
100 static const char slang_colors[][14] =
101 {
102     "black",
103     "blue",
104     "green",
105     "cyan",
106     "red",
107     "magenta",
108     "brown",
109     "lightgray",
110     "gray",
111     "brightblue",
112     "brightgreen",
113     "brightcyan",
114     "brightred",
115     "brightmagenta",
116     "yellow",
117     "white",
118 };
119 
120 static volatile int ScreenSizeChanged;
121 
sigwinch_handler(int sig)122 static void sigwinch_handler(int sig)
123 {
124     ScreenSizeChanged = 1;
125 }
126 
ConInit(int,int)127 int ConInit(int /*XSize */ , int /*YSize */ )
128 {
129     SLtt_get_terminfo();
130 
131     if ((SLkp_init() == -1)
132 	|| (SLang_init_tty(0, 1, 1) == -1))
133 	return 0;
134 
135     if (SLsmg_init_smg() == -1) {
136 	SLang_reset_tty();
137 	return 0;
138     }
139 
140     SLsignal_intr(SIGWINCH, sigwinch_handler);
141     SLang_set_abort_signal(NULL);
142     SLtty_set_suspend_state(0);
143 
144     /* skip modification of color 0 and 0x7f */
145     for (unsigned i = 1; i < 127; ++i)
146 	SLtt_set_color(i, NULL, const_cast<char *>(slang_colors[i & 0x0f]),
147 		       const_cast<char *>(slang_colors[(i >> 4) & 0x07]));
148 
149     SLsmg_gotorc(0, 0);
150     SLsmg_set_char_set(1);
151 
152     SLsmg_write_nchars(const_cast<char*>(slang_dchs), sizeof(slang_dchs));
153 
154     SLsmg_gotorc(0, 0);
155     SLsmg_read_raw(raw_dchs, sizeof(slang_dchs));
156     SLsmg_set_char_set(0);
157 
158 #ifdef CONFIG_MOUSE
159     SLtt_set_mouse_mode(1, 0);
160 #endif
161     SLtt_flush_output();
162     //use_esc_hack = (getenv("FTESL_ESC_HACK") != NULL);
163 
164     return 1;
165 }
ConDone()166 int ConDone()
167 {
168     SLsmg_reset_smg();
169     SLang_reset_tty();
170 
171     return 1;
172 }
173 
ConSuspend()174 int ConSuspend()
175 {
176     SLsmg_suspend_smg();
177     SLang_reset_tty();
178 
179     return 1;
180 }
ConContinue()181 int ConContinue()
182 {
183     SLang_init_tty(-1, 0, 1);
184     SLsmg_resume_smg();
185 
186     return 1;
187 }
188 
ConSetTitle(const char *,const char *)189 int ConSetTitle(const char * /*Title */ , const char * /*STitle */ )
190 {
191     return 1;
192 }
193 
ConGetTitle(char * Title,size_t MaxLen,char * STitle,size_t SMaxLen)194 int ConGetTitle(char *Title, size_t MaxLen, char *STitle, size_t SMaxLen)
195 {
196     strlcpy(Title, "", MaxLen);
197     strlcpy(STitle, "", SMaxLen);
198 
199     return 1;
200 }
201 
ConClear()202 int ConClear()
203 {
204     SLsmg_cls();
205     SLsmg_refresh();
206 
207     return 1;
208 }
209 
fte_write_color_chars(PCell Cell,int W)210 static void fte_write_color_chars(PCell Cell, int W)
211 {
212     int chset = 0, chsetprev = 2;
213     unsigned char ch, col = 0, colprev = 0x80;
214     char buf[256];
215 
216     while (W > 0) {
217 	int i;
218 	for (i = 0; i < W && i < (int)sizeof(buf); ++i) {
219 	    ch = Cell[i].GetChar();
220 	    col = Cell[i].GetAttr() & 0x7f;
221 	    //fprintf(stderr, "W: %d  i:%d  ch: %d %c  col: %2x / %2x\n", W, i, ch, ch, col, Cell[i].GetAttr() & 0x7f);
222 	    if (ch <= 127 || ch >= 0xa0) {
223 		buf[i] = (ch < 32) ? '.' : (char)ch;
224 		chset = 0;
225 	    } else {
226 		buf[i] = slang_dchs[ch - 128];
227 		chset = 1;
228 	    }
229 
230 	    if (col != colprev || chset != chsetprev)
231 		break;
232 	}
233 
234 	if (i > 0) {
235 	    SLsmg_write_nchars(buf, i);
236 	    W -= i;
237 	    Cell += i;
238 	}
239 
240 	if (col != colprev) {
241 	    SLsmg_set_color(col);
242 	    colprev = col;
243 	}
244 
245 	if (chset != chsetprev) {
246 	    SLsmg_set_char_set(chset);
247 	    chsetprev = chset;
248 	}
249     }
250 }
251 
ConPutBox(int X,int Y,int W,int H,PCell Cell)252 int ConPutBox(int X, int Y, int W, int H, PCell Cell)
253 {
254     int CurX, CurY;
255 
256     ConQueryCursorPos(&CurX, &CurY);
257     for (;H > 0; Cell += W, --H) {
258 	SLsmg_gotorc(Y++, X);
259 	fte_write_color_chars(Cell, W);
260     }
261     ConSetCursorPos(CurX, CurY);
262 
263     return 1;
264 }
265 
ConPutBoxRaw(int X,int Y,int W,int H,SLsmg_Char_Type * box)266 static int ConPutBoxRaw(int X, int Y, int W, int H, SLsmg_Char_Type *box)
267 {
268     int CurX, CurY;
269 
270     ConQueryCursorPos(&CurX, &CurY);
271     for (;H > 0; box += W, --H) {
272 	SLsmg_gotorc(Y++, X);
273 	SLsmg_write_raw(box, W);
274     }
275     ConSetCursorPos(CurX, CurY);
276 
277     return 1;
278 }
279 
ConGetBox(int X,int Y,int W,int H,PCell Cell)280 int ConGetBox(int X, int Y, int W, int H, PCell Cell)
281 {
282     int CurX, CurY, i;
283     SLsmg_Char_Type linebuf[W];
284 
285     ConQueryCursorPos(&CurX, &CurY);
286     for (;H > 0; Cell += W, --H) {
287 	SLsmg_gotorc(Y++, X);
288 	SLsmg_read_raw(linebuf, W);
289 	for (i = 0; i < W; i++) {
290 	    if (linebuf[i].color & SLSMG_ACS_MASK)
291 		Cell[i].SetChar(ftesl_get_dch(linebuf[i]));
292 	    else
293 		/*
294 		 * FIXME: Handle UTF-8 -- way beyond a quick-and-dirty
295 		 * fix.  --MV
296 		 */
297 		Cell[i].SetChar((char)SLSMG_EXTRACT_CHAR(linebuf[i]));
298 	    /*
299 	     * FIXME: This preserves only 7 out of 15 bits of color.
300 	     * Fortunately, we're dealing with color handles rather than
301 	     * colors themselves -- S-Lang jumps through an extra hoop to
302 	     * map these to color data.  As long as we use less than 127
303 	     * different colors, things should be OK.  I think.  --MV
304 	     */
305 	    Cell[i].SetAttr(linebuf[i].color & 0x7f);
306 	}
307     }
308     ConSetCursorPos(CurX, CurY);
309 
310     return 1;
311 }
312 
ConGetBoxRaw(int X,int Y,int W,int H,SLsmg_Char_Type * box)313 static int ConGetBoxRaw(int X, int Y, int W, int H, SLsmg_Char_Type *box)
314 {
315     int CurX, CurY;
316 
317     ConQueryCursorPos(&CurX, &CurY);
318     for (;H > 0; box += W, --H) {
319 	SLsmg_gotorc(Y++, X);
320 	SLsmg_read_raw(box, W);
321     }
322     ConSetCursorPos(CurX, CurY);
323 
324     return 1;
325 }
326 
ConPutLine(int X,int Y,int W,int H,PCell Cell)327 int ConPutLine(int X, int Y, int W, int H, PCell Cell)
328 {
329     int CurX, CurY;
330 
331     ConQueryCursorPos(&CurX, &CurY);
332     for (;H > 0; --H) {
333 	SLsmg_gotorc(Y++, X);
334 	fte_write_color_chars(Cell, W);
335     }
336     ConSetCursorPos(CurX, CurY);
337 
338     return 1;
339 }
340 
ConSetBox(int X,int Y,int W,int H,TCell Cell)341 int ConSetBox(int X, int Y, int W, int H, TCell Cell)
342 {
343     TCell line[W];
344 
345     for (int i = 0; i < W; i++)
346 	line[i] = Cell;
347 
348     ConPutLine(X, Y, W, H, line);
349 
350     return 1;
351 }
352 
ConScroll(int Way,int X,int Y,int W,int H,TAttr Fill,int Count)353 int ConScroll(int Way, int X, int Y, int W, int H, TAttr Fill, int Count)
354 {
355     SLsmg_Char_Type box[W * H];
356     TCell fill(' ', Fill);
357 
358     ConGetBoxRaw(X, Y, W, H, box);
359 
360     if (Way == csUp) {
361 	ConPutBoxRaw(X, Y, W, H - Count, box + W * Count);
362 	//ConSetBox(X, Y + H - Count, W, Count, fill);
363     } else {
364 	ConPutBoxRaw(X, Y + Count, W, H - Count, box);
365 	//ConSetBox(X, Y, W, Count, fill);
366     }
367 
368     return 1;
369 }
370 
ConSetSize(int,int)371 int ConSetSize(int /*X */ , int /*Y */ )
372 {
373     return 0;
374 }
375 
ConQuerySize(int * X,int * Y)376 int ConQuerySize(int *X, int *Y)
377 {
378     *X = SLtt_Screen_Cols;
379     *Y = SLtt_Screen_Rows;
380 
381     return 1;
382 }
383 
ConSetCursorPos(int X,int Y)384 int ConSetCursorPos(int X, int Y)
385 {
386     SLsmg_gotorc(Y, X);
387     SLsmg_refresh();
388     return 1;
389 }
390 
ConQueryCursorPos(int * X,int * Y)391 int ConQueryCursorPos(int *X, int *Y)
392 {
393     *X = SLsmg_get_column();
394     *Y = SLsmg_get_row();
395     return 1;
396 }
397 
398 static int CurVis = 1;
399 
ConShowCursor()400 int ConShowCursor()
401 {
402     CurVis = 1;
403     SLtt_set_cursor_visibility(1);
404 
405     return 1;
406 }
ConHideCursor()407 int ConHideCursor()
408 {
409     CurVis = 0;
410     SLtt_set_cursor_visibility(0);
411 
412     return 1;
413 }
ConCursorVisible()414 int ConCursorVisible()
415 {
416     return CurVis;
417 }
418 
ConSetCursorSize(int,int)419 int ConSetCursorSize(int /*Start */ , int /*End */ )
420 {
421     return 1;
422 }
423 
ConSetMousePos(int,int)424 int ConSetMousePos(int /*X */ , int /*Y */ )
425 {
426     return 0;
427 }
ConQueryMousePos(int * X,int * Y)428 int ConQueryMousePos(int *X, int *Y)
429 {
430     *X = 0;
431     *Y = 0;
432 
433     return 1;
434 }
435 
ConShowMouse()436 int ConShowMouse()
437 {
438     return 0;
439 }
440 
ConHideMouse()441 int ConHideMouse()
442 {
443     return 0;
444 }
445 
ConMouseVisible()446 int ConMouseVisible()
447 {
448     return 1;
449 }
450 
ConQueryMouseButtons(int * ButtonCount)451 int ConQueryMouseButtons(int *ButtonCount)
452 {
453     *ButtonCount = 0;
454 
455     return 1;
456 }
457 
getkey(int tsecs)458 static int getkey(int tsecs)
459 {
460     int key;
461 
462     if (SLang_input_pending(tsecs) > 0) {
463 	key = SLang_getkey();
464 	//fprintf(stderr, "readkey  0x%2x  %d  %c\n", key, key, isprint(key) ? key : ' ');
465     } else
466 	key = 0;
467 
468     return key;
469 }
470 
parseEsc(TEvent * Event)471 static int parseEsc(TEvent *Event)
472 {
473     int key = getkey(0);
474     char seq[8] = { (char)key, 0 };
475     unsigned seqpos = 1;
476 
477     if ((key < 'a' && key) || key > 'z') {
478 	/* read whole Esc sequence */
479 	while (seqpos < 7 && (seq[seqpos] = (char)getkey(0))) {
480 	    if ((unsigned char)seq[seqpos] < ' ') {
481 		SLang_ungetkey((unsigned char)seq[seqpos]);
482 		break;
483 	    }
484 	    seqpos++;
485 	}
486 	seq[seqpos] = 0;
487     }
488     //if (seqpos > 1) fprintf(stderr, "Seq: %d  %s\n", seqpos, seq);
489     if (seqpos == 5 && seq[0] == '[' && seq[1] == 'M') {
490 #ifdef CONFIG_MOUSE
491 	// FIXME: hardcoded timeouts
492 	static const int64_t timeout[] = {
493 	    300000,// 300ms  double
494 	    500000,// 500ms  tripple
495 	    700000,// 700ms  4 clicks
496 	    900000 // 900ms  5 clicks
497 	};
498 	static int64_t time_prev[FTE_ARRAY_SIZE(timeout)];
499 	struct timeval tv;
500 	gettimeofday(&tv, NULL);
501 	int64_t time_new = tv.tv_sec * 1000000 + tv.tv_usec;
502 
503 	// only mouse clicks are reported
504 	Event->Mouse.What = evMouseDown;
505 	Event->Mouse.X = (unsigned char)seq[3] - 33;
506 	Event->Mouse.Y = (unsigned char)seq[4] - 33;
507 	Event->Mouse.Buttons = (seq[2] == 32) ? 1 : (seq[2] == 33) ? 4 : 2;
508 
509 	// FIXME: this code should be moved to upper layer
510 	// detect 2,3,4 mouse clicks
511 	Event->Mouse.Count = 1;
512 	for (size_t i = 0; i < FTE_ARRAY_SIZE(timeout)
513              && ((time_new - time_prev[i]) < timeout[i]); ++i)
514 		Event->Mouse.Count++;
515 	for (size_t i = FTE_ARRAY_SIZE(timeout); --i > 0;)
516 	    time_prev[i] = time_prev[i - 1];
517 	time_prev[0] = time_new;
518 	//fprintf(stderr, "B:%2d:%d  X:%3d  Y:%3d  Time %"PRId64 "\n",
519 	//	Event->Mouse.Buttons, Event->Mouse.Count, Event->Mouse.X, Event->Mouse.Y, time_new);
520 
521 	if (seq[2] & 0x40) {
522 	    Event->What = evCommand;
523 	    Event->Msg.Param1 = 10;
524 	    Event->Msg.Command = (seq[2] & 1) ? cmVScrollDown : cmVScrollUp;
525 	} else {
526 	    NextEvent = *Event;
527 	    NextEvent.Mouse.What = evMouseUp;
528 	}
529 #endif // CONFIG_MOUSE
530 	return 1;
531     }
532 
533     return TTYParseEsc(seq);
534 }
535 
536 static TEvent Prev = { evNone };
537 
ConGetEvent(TEventMask,TEvent * Event,int WaitTime,int Delete)538 int ConGetEvent(TEventMask /*EventMask */ ,
539 		TEvent * Event, int WaitTime, int Delete)
540 {
541     TKeyEvent& KEvent = Event->Key;
542     int key;
543 
544     if (ScreenSizeChanged) {
545 	ScreenSizeChanged = 0;
546 	SLtt_get_screen_size();
547 	SLsmg_reinit_smg();
548 	Event->What = evCommand;
549 	Event->Msg.Command = cmResize;
550 	return 1;
551     }
552 
553     if (Prev.What != evNone) {
554 	*Event = Prev;
555 	if (Delete)
556 	    Prev.What = evNone;
557 	return 1;
558     }
559 
560     WaitTime = (WaitTime >= 0) ? WaitTime / 100 : 36000;
561 
562     switch (WaitFdPipeEvent(Event, STDIN_FILENO, -1, WaitTime)) {
563     case FD_PIPE_1: break;
564     default: return 0;
565     }
566 
567     Event->What = evKeyDown;
568 
569     key = getkey(0);
570     if (isupper(key))
571 	key = kfShift | key;
572     else if (key < 32) {
573 	switch (key) {
574 	case 0:
575 	    Event->What = evNone;
576 	    return -1;
577 	case 8:
578 	    key = kbBackSp;
579 	    break;
580 	case '\t':
581 	    key = kbTab;
582 	    break;
583 	case '\r':
584 	case '\n':
585 	    key = kbEnter;
586 	    break;
587 	case 27: // Esc
588 	    key = parseEsc(Event);
589 	    break;
590 	default:
591 	    key = kfCtrl | (key + 'A' - 1);
592 	}
593     } else if (key == 127)
594 	key = kbBackSp;
595     else if (key > 255)
596 	key = kbEsc;
597 
598     if (Event->What == evKeyDown) {
599 	KEvent.Code = key;
600     //fprintf(stderr, "KEY %x \n", key);
601 
602 	if (!Delete)
603 	    Prev = *Event;
604     }
605 
606     return 1;
607 }
608 
ConPutEvent(const TEvent & Event)609 int ConPutEvent(const TEvent& Event)
610 {
611     Prev = Event;
612 
613     return 1;
614 }
615 
GUI(int & argc,char ** argv,int XSize,int YSize)616 GUI::GUI(int &argc, char **argv, int XSize, int YSize)
617 {
618     fArgc = argc;
619     fArgv = argv;
620     if (TTYInitTable() == 0) {
621 	::ConInit(-1, -1);
622 	::ConSetSize(XSize, YSize);
623 	gui = this;
624     }
625 }
626 
~GUI()627 GUI::~GUI()
628 {
629     ::ConDone();
630     gui = 0;
631 }
632 
ConSuspend()633 int GUI::ConSuspend()
634 {
635     return::ConSuspend();
636 }
637 
ConContinue()638 int GUI::ConContinue()
639 {
640     return::ConContinue();
641 }
642 
ShowEntryScreen()643 int GUI::ShowEntryScreen()
644 {
645     TEvent E;
646 
647     ConHideMouse();
648     do {
649 	gui->ConGetEvent(evKeyDown, &E, -1, 1, 0);
650     } while (E.What != evKeyDown);
651     ConShowMouse();
652     if (frames)
653 	frames->Repaint();
654 
655     return 1;
656 }
657 
RunProgram(int,char * Command)658 int GUI::RunProgram(int /*mode */ , char *Command)
659 {
660     int rc, W, H, W1, H1;
661 
662     ConQuerySize(&W, &H);
663     ConHideMouse();
664     ConSuspend();
665 
666     if (*Command == 0)		// empty string = shell
667 	Command = getenv("SHELL");
668 
669     rc = system(Command);
670 
671     ConContinue();
672     ConShowMouse();
673     ConQuerySize(&W1, &H1);
674 
675     if (W != W1 || H != H1)
676 	frames->Resize(W1, H1);
677 
678     frames->Repaint();
679 
680     return rc;
681 }
682 
ConGetDrawChar(unsigned int idx)683 char ConGetDrawChar(unsigned int idx)
684 {
685     static const unsigned char tab[] = {
686 	DCH_SLANG_C1,
687 	DCH_SLANG_C2,
688 	DCH_SLANG_C3,
689 	DCH_SLANG_C4,
690 	DCH_SLANG_H,
691 	DCH_SLANG_V,
692 	DCH_SLANG_M1,
693 	DCH_SLANG_M2,
694 	DCH_SLANG_M3,
695 	DCH_SLANG_M4,
696 	DCH_SLANG_X,
697 	'>', // DCH_SLANG_RPTR
698 	DCH_SLANG_EOL,
699 	DCH_SLANG_EOF,
700 	DCH_SLANG_END,
701 	DCH_SLANG_AUP,
702 	DCH_SLANG_ADOWN,
703 	DCH_SLANG_HFORE,
704 	DCH_SLANG_HBACK,
705 	DCH_SLANG_ALEFT,
706 	DCH_SLANG_ARIGHT
707     };
708 
709     static const unsigned char tab_linux[] = {
710 	DCH_SLANG_C1,
711 	DCH_SLANG_C2,
712 	DCH_SLANG_C3,
713 	DCH_SLANG_C4,
714 	DCH_SLANG_H,
715 	DCH_SLANG_V,
716 	DCH_SLANG_M1,
717 	DCH_SLANG_M2,
718 	DCH_SLANG_M3,
719 	DCH_SLANG_M4,
720 	DCH_SLANG_X,
721 	'>',
722 	'.',
723 	DCH_SLANG_EOF,
724 	DCH_SLANG_END,
725 	DCH_SLANG_AUP,
726 	DCH_SLANG_ADOWN,
727 	DCH_SLANG_HFORE,
728 	DCH_SLANG_HBACK,
729 	DCH_SLANG_ALEFT,
730 	DCH_SLANG_ARIGHT
731     };
732 #if 0
733     static const unsigned char tab[] = {
734 	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
735 	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k',
736 	'l', 'm', 'n', 'o', 'p', 'q'
737     };
738 #endif
739     static const char *use_tab;
740     static size_t use_tab_size;
741 
742     if (!use_tab) {
743 	const char *c = getenv("TERM");
744 	use_tab = (const char*)
745 	    ((!c || strcmp(c, "linux") != 0) ? tab : tab_linux);
746 	use_tab = GetGUICharacters("Slang", use_tab);
747 	use_tab_size = strlen(use_tab);
748     }
749 
750     assert(idx < use_tab_size);
751 
752     return use_tab[idx];
753 }
754 
755 /*
756  * Code bellow is no longer needed
757  * - will be removed in future
758  */
759 #if 0
760     if (SLang_input_pending(0) > 0) {
761 	TKeyCode kcode = 0, kcode1;
762 
763 	key = SLang_getkey();
764 	int escfirst = 1;
765 
766 	if (key == 27)
767 	    while (1) {
768 		if (use_esc_hack) {
769 		    if (SLang_input_pending(1) == 0) {
770 			kcode = kbEsc;
771 			break;
772 		    }
773 		}
774 
775 		key = SLang_getkey();
776 		if (key == 3) {
777 		    SLang_ungetkey((unsigned char)key);
778 		    SLkp_getkey();
779 		}
780 		if (key >= 'a' && key <= 'z')
781 		    key -= 'a' - 'A';
782 		if (key == 27) {
783 		    kcode = kbEsc;
784 		    break;
785 		} else if (key == '[' && escfirst) {
786 		    unsigned char kbuf[2];
787 
788 		    kbuf[0] = 27;
789 		    kbuf[1] = (char) key;
790 		    SLang_ungetkey_string(kbuf, 2);
791 		    key = SLkp_getkey();
792 		    if (key == 0xFFFF) {
793 			if (SLang_input_pending(0) == 0) {
794 			    /*
795 			     * SLang got an unknown key and ate it.
796 			     * beep and bonk out.
797 			     */
798 			    SLtt_beep();
799 			    return -1;
800 			}
801 			/*
802 			 * SLang encountered an unknown key sequence, so we
803 			 * try to parse the sequence one by one and thus
804 			 * enable the user to configure a binding for it
805 			 */
806 			key = SLang_getkey();
807 			if (key != 27) {
808 			    SLtt_beep();
809 			    SLang_flush_input();
810 			    return -1;
811 			}
812 		    }
813 		    kcode = ftesl_process_key(key, 0);
814 		    break;
815 		} else {
816 		    kcode1 = ftesl_process_key(key, 1);
817 		    if (keyCode(kcode1) == kbF1) {
818 			key = SLang_getkey();
819 			switch (key) {
820 			case '0':
821 			    kcode |= kbF10;
822 			    break;
823 			case '1':
824 			case '2':
825 			case '3':
826 			case '4':
827 			case '5':
828 			case '6':
829 			case '7':
830 			case '8':
831 			case '9':
832 			    kcode |= kbF1 + key - '1';
833 			    break;
834 			case 'a':
835 			case 'b':
836 			    kcode |= kbF11 + key - 'a';
837 			    break;
838 			}
839 		    } else
840 			kcode |= kcode1;
841 
842 		    if (keyCode(kcode) != 0) {
843 			if (escfirst)
844 			    kcode |= kfAlt;
845 			break;
846 		    }
847 		}
848 		escfirst = 0;
849 	} else {
850 	    SLang_ungetkey((unsigned char)key);
851 	    key = SLkp_getkey();
852 	    kcode = ftesl_process_key(key, 0);
853 	}
854 
855 	Event->What = evKeyDown;
856 	KEvent->Code = kcode;
857 
858 	if (!Delete)
859 	    Prev = *Event;
860 
861 	return 1;
862     }
863 
864     return -1;
865 #endif
866 
867 #if 0
868 /*
869  * Definitions for keyboard handling under SLang.
870  */
871 
872 #define FTESL_KEY            0x00001000		// A key defined by me
873 #define FTESL_KEY_SHIFT      0x00002000		// Key with Shift
874 #define FTESL_KEY_CTRL       0x00004000		// Key with Ctrl
875 #define FTESL_KEY_ALT        0x00008000		// Key with Alt
876 #define FTESL_KEY_GRAY       0x00010000		// Gray Key
877 
878 #define FTESL_KEY_ENTER      13
879 #define FTESL_KEY_TAB         9
880 #define FTESL_KEY_ESC        27
881 #define FTESL_KEY_BACKSP      8
882 
883 #define FTESL_KEY_CTRLAND(x)    (x+1-'a')
884 
885 static int use_esc_hack = 0;
886 
887 static const TKeyCode speckeys[] =
888 {
889     kbF1,
890     kbF2,
891     kbF3,
892     kbF4,
893     kbF5,
894     kbF6,
895     kbF7,
896     kbF8,
897     kbF9,
898     kbF10,
899     kbF11,
900     kbF12,
901     kbHome,
902     kbEnd,
903     kbPgUp,
904     kbPgDn,
905     kbIns,
906     kbDel,
907     kbUp,
908     kbDown,
909     kbLeft,
910     kbRight,
911     kbEnter,
912     kbEsc,
913     kbBackSp,
914     kbSpace,
915     kbTab,
916     kbCenter,
917 };
918 
919 /*
920 static int ftesl_getkeysym(TKeyCode keycode)
921 {
922     unsigned key = keyCode(keycode);
923     int ksym = -1;
924 
925     for (unsigned i = 0; i < sizeof(speckeys) / sizeof(TKeyCode); i++) {
926 	if (key == speckeys[i]) {
927 	    ksym = (int) i;
928 	    break;
929 	}
930     }
931 
932     if (ksym < 0 && key < 256) {
933 	ksym = (int) key;
934     }
935 
936     if (ksym < 0)
937 	return ksym;
938 
939     if (keycode & kfAlt)
940 	ksym |= FTESL_KEY_ALT;
941     if (keycode & kfCtrl)
942 	ksym |= FTESL_KEY_CTRL;
943     if (keycode & kfShift)
944 	ksym |= FTESL_KEY_SHIFT;
945     if (keycode & kfGray)
946 	ksym |= FTESL_KEY_GRAY;
947 
948     ksym |= FTESL_KEY;
949     return ksym;
950 }
951 */
952 
953 static const TKeyCode keys_ctrlhack[] =
954 {
955     kfAlt,  // A
956     kbHome, // B
957     kfCtrl,
958     kbDown,
959     kbEnd,
960 
961     kbF1,
962     kfCtrl | 'G',
963     kbBackSp,
964     kbTab,
965     kfCtrl | 'J',
966 
967     kfCtrl | 'K',
968     kbLeft,
969     kbEnter,
970     kbPgDn,
971     kfCtrl | 'O',
972 
973     kbPgUp,
974     kbIns,
975     kbRight,
976     kfShift,
977     kfCtrl | 'T',
978 
979     kbUp,
980     kfCtrl | 'V',
981     kfCtrl | 'W',
982     kbCenter,
983     kfCtrl | 'Y',
984 
985     kbDel,
986     kbEsc,
987     kbCtrl | '\\',
988     kbCtrl | ']',
989     kbCtrl | '^',
990     kbCtrl | '_'
991 };
992 
993 static TKeyCode ftesl_getftekey(unsigned char key)
994 {
995     if (key < 32)
996 	return speckeys[key];
997     else
998 	return (TKeyCode) key;
999 }
1000 
1001 /*
1002  * Keyboard handling with SLang.
1003  */
1004 static TKeyCode ftesl_process_key(int key, int ctrlhack = 0)
1005 {
1006     TKeyCode kcode;
1007 
1008     //fprintf(stderr, "KEY  %03d \n", key);
1009     if (key < 256 && key >= 32) {
1010 	return (TKeyCode) key;
1011     } else if (key >= 1 && key <= 31 && key != 13 && key != 9 && key != 8
1012 	       && key != 27) {
1013 	if (!ctrlhack)
1014 	    return ((key + 'A' - 1) & 0xff) | kfCtrl;
1015 	else
1016 	    return keys_ctrlhack[key - 1];
1017     } else if (key & FTESL_KEY) {
1018 	kcode = ftesl_getftekey((unsigned char)key);
1019 	if (key & FTESL_KEY_SHIFT)
1020 	    kcode |= kfShift;
1021 	if (key & FTESL_KEY_CTRL)
1022 	    kcode |= kfCtrl;
1023 	if (key & FTESL_KEY_ALT)
1024 	    kcode |= kfAlt;
1025 	if (key & FTESL_KEY_GRAY)
1026 	    kcode |= kfGray;
1027 	return kcode;
1028     } else
1029 	switch (key) {
1030 	case SL_KEY_UP:
1031 	    return kbUp;
1032 	case SL_KEY_DOWN:
1033 	    return kbDown;
1034 	case SL_KEY_LEFT:
1035 	    return kbLeft;
1036 	case SL_KEY_RIGHT:
1037 	    return kbRight;
1038 	case SL_KEY_PPAGE:
1039 	    return kbPgUp;
1040 	case SL_KEY_NPAGE:
1041 	    return kbPgDn;
1042 	case SL_KEY_HOME:
1043 	    return kbHome;
1044 	case SL_KEY_END:
1045 	    return kbEnd;
1046 	case SL_KEY_BACKSPACE:
1047 	case FTESL_KEY_BACKSP:
1048 	    return kbBackSp;
1049 	case SL_KEY_ENTER:
1050 	case FTESL_KEY_ENTER:
1051 	    return kbEnter;
1052 	case SL_KEY_IC:
1053 	    return kbIns;
1054 	case SL_KEY_DELETE:
1055 	    return kbDel;
1056 	case SL_KEY_F(1):
1057 	    return kbF1;
1058 	case SL_KEY_F(2):
1059 	    return kbF2;
1060 	case SL_KEY_F(3):
1061 	    return kbF3;
1062 	case SL_KEY_F(4):
1063 	    return kbF4;
1064 	case SL_KEY_F(5):
1065 	    return kbF5;
1066 	case SL_KEY_F(6):
1067 	    return kbF6;
1068 	case SL_KEY_F(7):
1069 	    return kbF7;
1070 	case SL_KEY_F(8):
1071 	    return kbF8;
1072 	case SL_KEY_F(9):
1073 	    return kbF9;
1074 	case SL_KEY_F(10):
1075 	    return kbF10;
1076 	case SL_KEY_F(11):
1077 	    return kbF11;
1078 	case SL_KEY_F(12):
1079 	    return kbF12;
1080 	case FTESL_KEY_TAB:
1081 	    return kbTab;
1082 	case FTESL_KEY_ESC:
1083 	case SL_KEY_ERR:
1084 	    return kbEsc;
1085 	default:
1086 	    return '?';
1087 	}
1088 }
1089 #endif
1090