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