1 /*======================================================================*\
2 |*		Editor mined						*|
3 |*		keyboard input						*|
4 \*======================================================================*/
5 
6 #include "mined.h"
7 #include "charprop.h"
8 #include "io.h"
9 #include "termprop.h"
10 
11 #define dont_debug_mouse
12 
13 
14 #if ! defined (__TURBOC__) && ! defined (VAXC)
15 #include <sys/time.h>
16 #endif
17 
18 #ifdef vms
19 #undef CURSES
20 #endif
21 
22 #ifdef CURSES
23 #include <curses.h>
24 #include <strings.h>
25 #endif
26 
27 
28 voidfunc keyproc = I;	/* function addressed by entered function key */
29 unsigned char keyshift = 0;	/* shift state of entered function key */
30 static unsigned char fkeyshift;
31 #define max_ansi_params 10
32 int ansi_params;
33 int ansi_param [max_ansi_params];
34 char ansi_ini;
35 char ansi_fini;
36 
37 static
38 int keymap_delay = 0;		/* wait to detect mapped key sequence */
39 static
40 int default_keymap_delay = 900;	/* overridden by $MAPDELAY */
41 
42 static
43 int escape_delay = 0;		/* wait to detect escape sequence */
44 static
45 int default_escape_delay = 450;	/* overridden by $ESCDELAY */
46 
47 static
48 int dont_suppress_keymap = 1;
49 
50 static
51 int report_winchg = 0;
52 
53 /* The flag queue_mode_mapped indicates when the byte input queue
54    has been stuffed with keyboard mapped characters, always being
55    encoded in UTF-8, while otherwise the queue contents are in
56    terminal native encoding (which may also be UTF-8, or CJK, or Latin-1).
57  */
58 static
59 FLAG queue_mode_mapped = False;	/* queue contains mapped character(s) */
60 
61 /* In hp_shift_mode key shift indications like ESC 2p or ESC 5h
62    are considered to determine the keyshift state.
63  */
64 static
65 FLAG hp_shift_mode = False;
66 
67 /* In sco_shift_mode key shift indications like ESC [2A or ESC [2M
68    are considered to determine the keyshift state.
69  */
70 static
71 FLAG sco_shift_mode = False;
72 
73 /* mouse handling */
74 mousebutton_type mouse_button;
75 mousebutton_type mouse_prevbutton = movebutton;
76 int mouse_xpos, mouse_ypos, mouse_prevxpos, mouse_prevypos;
77 int mouse_shift = 0;		/* modifier status */
78 FLAG report_release = False;	/* selectively suppress release event */
79 FLAG window_focus = True;	/* does the window have mouse/keyboard focus? */
80 int mouse_buttons_pressed = 0;	/* count pressed buttons */
81 
82 
83 /*======================================================================*\
84 |*		Local function declaration				*|
85 \*======================================================================*/
86 
87 static unsigned long _readchar _((void));
88 
89 
90 /*======================================================================*\
91 |*		Function key tables					*|
92 \*======================================================================*/
93 
94 #define dont_debug_findkey
95 
96 
97 #ifndef msdos
98 
99 #ifdef unix
100 #define TERMINFO
101 #endif
102 
103 static
104 void
dummyfunc()105 dummyfunc ()
106 {
107 }
108 
109 extern struct fkeyentry fkeymap [];
110 extern struct fkeyentry fkeymap_xterm [];
111 extern struct fkeyentry fkeymap_rxvt [];
112 extern struct fkeyentry fkeymap_linux [];
113 extern struct fkeyentry fkeymap_vt100 [];
114 extern struct fkeyentry fkeymap_vt52 [];
115 extern struct fkeyentry fkeymap_hp [];
116 extern struct fkeyentry fkeymap_siemens [];
117 extern struct fkeyentry fkeymap_scoansi [];
118 extern struct fkeyentry fkeymap_interix [];
119 
120 static struct fkeyentry * fkeymap_spec = fkeymap_xterm;
121 #ifdef TERMINFO
122 extern struct fkeyentry fkeymap_terminfo [];
123 #endif
124 
125 void
set_fkeymap(term)126 set_fkeymap (term)
127   char * term;
128 {
129 #ifdef debug_findkey
130   printf ("set_fkeymap %s\n", term);
131 #endif
132 
133   if (term == NIL_PTR) {
134 	fkeymap_spec = fkeymap;
135   } else if (* term == 'x') {
136 	fkeymap_spec = fkeymap_xterm;
137   } else if (* term == 'r') {
138 	fkeymap_spec = fkeymap_rxvt;
139   } else if (* term == 'l') {
140 	fkeymap_spec = fkeymap_linux;
141   } else if (* term == 'h') {
142 	fkeymap_spec = fkeymap_hp;
143 	hp_shift_mode = True;
144   } else if (* term == 'v') {
145 	fkeymap_spec = fkeymap_vt100;
146   } else if (* term == '5') {
147 	fkeymap_spec = fkeymap_vt52;
148   } else if (* term == 'i') {
149 	fkeymap_spec = fkeymap_interix;
150   } else if (* term == 's') {
151 	fkeymap_spec = fkeymap_siemens;
152 	use_mouse = False;
153   } else if (* term == 'o') {
154 	fkeymap_spec = fkeymap_scoansi;
155 	sco_shift_mode = True;
156 	use_mouse = False;
157   }
158 }
159 
160 #else
161 
162 void
set_fkeymap(term)163 set_fkeymap (term)
164   char * term;
165 {
166 }
167 
168 #endif
169 
170 
171 /*======================================================================*\
172 |*		String input functions					*|
173 \*======================================================================*/
174 
175 /**
176    get_digits () reads in a number.
177    In contrast to get_number, it does no echoing, no messaging, reads
178    only decimal, and accepts zero length input.
179    The last character typed in is returned.
180    The resulting number is put into the integer the arguments points to.
181    It is for use within I/O routines (e.g. reading mouse escape sequences
182    or cursor position report) and thus calls read1byte / __readchar.
183  */
184 int
get_digits(result)185 get_digits (result)
186   int * result;
187 {
188   register int byte1;
189   register int value;
190 
191   byte1 = read1byte ();
192   * result = -1;
193 /* Convert input to a decimal number */
194   value = 0;
195   while (byte1 >= '0' && byte1 <= '9') {
196 	value *= 10;
197 	value += byte1 - '0';
198 	* result = value;
199 	byte1 = read1byte ();
200   }
201 
202   return byte1;
203 }
204 
205 
206 /**
207    get_string_nokeymap prompts a string like get_string
208    but doesn't apply international keyboard mapping
209  */
210 int
get_string_nokeymap(prompt,inbuf,statfl,term_input)211 get_string_nokeymap (prompt, inbuf, statfl, term_input)
212   char * prompt;
213   char * inbuf;
214   FLAG statfl;
215   char * term_input;
216 {
217   int ret;
218 
219   dont_suppress_keymap = 0;
220   ret = get_string (prompt, inbuf, statfl, term_input);
221   dont_suppress_keymap = 1;
222 
223   return ret;
224 }
225 
226 
227 /*======================================================================*\
228 |*			Terminal input					*|
229 \*======================================================================*/
230 
231 #ifdef debug_keytrack
232 
233 void
do_trace_keytrack(tag,c)234 do_trace_keytrack (tag, c)
235   char * tag;
236   unsigned long c;
237 {
238   printf ("[%s] ", tag);
239   if (command (c) == COMPOSE) {
240 	printf ("COMPOSE");
241   } else if (c == FUNcmd) {
242 	printf ("FUNcmd");
243   } else {
244 	printf ("%02lX", c);
245   }
246   printf (" [keyshift %X]\n", keyshift);
247 }
248 
249 #endif
250 
251 #define dont_debug_mapped_keyboard
252 
253 #define max_stamps 10
254 static long last_sec = 0;
255 static long last_msec = 0;
256 static int n_stamps = 0;
257 static int i_stamp = 0;
258 static long stamps [max_stamps];
259 static long total_deltas = 0;
260 long average_delta_readchar = 0;
261 long last_delta_readchar = 0;
262 
263 static FLAG skip_1click = False;
264 static FLAG skip_1release = False;
265 
266 
267 static
268 void
timestamp_readchar()269 timestamp_readchar ()
270 {
271 #if ! defined (__TURBOC__) && ! defined (VAXC)
272   struct timeval now;
273   long sec;
274   long msec;
275 
276   gettimeofday (& now, 0);
277   sec = now.tv_sec;
278   msec = now.tv_usec / 1000;
279   if (last_sec == 0) {
280 	last_delta_readchar = 1000;
281   } else {
282 	last_delta_readchar = (sec - last_sec) * 1000 + msec - last_msec;
283   }
284   last_sec = sec;
285   last_msec = msec;
286 
287   if (n_stamps < max_stamps) {
288 	n_stamps ++;
289   } else {
290 	/* remove oldest stamp from statistics */
291 	total_deltas -= stamps [i_stamp];
292   }
293   stamps [i_stamp] = last_delta_readchar;
294   /* add stamp to statistics */
295   total_deltas += last_delta_readchar;
296   i_stamp ++;
297   if (i_stamp == max_stamps) {
298 	i_stamp = 0;
299   }
300 
301   average_delta_readchar = total_deltas / n_stamps;
302 #endif
303 }
304 
305 /*
306  * Readchar () reads one character from the terminal.
307  * There are problems due to interruption of the read operation by signals
308  * (QUIT, WINCH). The waitingforinput flag is only a partial solution.
309  * Unix doesn't provide sufficient facilities to handle these situations
310  * neatly and properly. Moreover, different Unix versions yield different
311  * surprising effects. However, the use of select () could still be
312  * an improvement.
313  */
314 static
315 unsigned long
readchar()316 readchar ()
317 {
318   unsigned long c;
319 
320 #ifdef msdos
321 #define winchhere
322 #endif
323 
324 #ifdef winchhere
325   FLAG waiting;
326 
327   if (winchg && waitingforinput == False) {
328 	/* In the Unix version, this is now done in __readchar () */
329 	RDwinchg ();
330   }
331   /* must save waitingforinput flag since in the MSDOS version,
332      readchar can be called recursively */
333   waiting = waitingforinput;
334 #endif
335   waitingforinput = True;
336 
337   c = _readchar ();
338   trace_keytrack ("readchar:_readchar", c);
339   /* check report_release to suppress subsequent release actions
340      (esp after menu item selection)
341      when multiple buttons are pressed simultaneously */
342   while (report_release == False &&
343 	 command (c) == MOUSEfunction && mouse_button == releasebutton)
344   {
345 	last_mouse_event = releasebutton;
346 #ifdef debug_mouse
347 	printf ("readchar: ignoring mouse release (report_release == False)\n");
348 #endif
349 	c = _readchar ();
350   }
351 #ifdef debug_mouse
352   printf ("readchar: report_release = False\n");
353 #endif
354   report_release = False;
355 
356 #ifdef winchhere
357   waitingforinput = waiting;
358 #else
359   waitingforinput = False;
360 #endif
361 
362   /* the modification
363 	if (quit) {
364 		c = quit_char;
365 	}
366      (now in __readchar) must not be placed after resetting the flag
367 	waitingforinput = False;
368      Otherwise a QUIT signal coming in just between these two would
369      discard the last valid character just taken up.
370   */
371 
372   timestamp_readchar ();
373 
374   return c;
375 }
376 
377 /*
378    readchar_nokeymap reads like readchar
379    but doesn't apply international keyboard mapping
380  */
381 static
382 unsigned long
readchar_nokeymap()383 readchar_nokeymap ()
384 {
385   unsigned long c;
386   int prev_dont_suppress_keymap = dont_suppress_keymap;
387 
388   dont_suppress_keymap = 0;
389   c = readchar ();
390   dont_suppress_keymap = prev_dont_suppress_keymap;
391 
392   return c;
393 }
394 
395 /*
396    readcharacter_mapping () reads one character
397    either with or without keyboard mapping
398  */
399 static
400 unsigned long
readcharacter_mapping(map_keyboard,return_unicode)401 readcharacter_mapping (map_keyboard, return_unicode)
402   FLAG map_keyboard;
403   FLAG return_unicode;
404 {
405   int utfcount = 1;
406   unsigned long unichar;
407 
408   if (map_keyboard) {
409 	unichar = readchar ();
410   } else {
411 	unichar = readchar_nokeymap ();
412 	trace_keytrack ("readcharacter:readchar_nokeymap", unichar);
413 	/* double check needed here because command ('\n') == SNL */
414 	if (unichar == FUNcmd && command (unichar) == SNL) {
415 		return '\r';
416 	}
417   }
418 
419   if (unichar == FUNcmd) {
420 	/** housekeeping of some events to cover the cases:
421 		focus-out mouse-click focus-in mouse-release (xterm 224)
422 		focus-out mouse-click mouse-release focus-in
423 		focus-out focus-in mouse-click mouse-release
424 	    and ignore the first mouse click/release in any case
425 	 */
426 	FLAG skipmouse = False;
427 
428 	if (command (unichar) == FOCUSout) {
429 #ifdef debug_mouse
430 		printf ("FOCUS out\n");
431 #endif
432 		FOCUSout ();
433 		skip_1click = True;
434 		skip_1release = True;
435 		skipmouse = True;
436 	} else if (command (unichar) == FOCUSin) {
437 #ifdef debug_mouse
438 		printf ("FOCUS in\n");
439 #endif
440 		FOCUSin ();
441 		skipmouse = True;
442 		return FUNcmd;
443 	} else if (command (unichar) == MOUSEfunction) {
444 		if (mouse_button != releasebutton
445 		    && last_delta_readchar > 100 && skip_1click) {
446 			/* skip click only immediately after focus in */
447 			skip_1click = False;
448 			skip_1release = False;
449 		}
450 
451 		if (mouse_button == releasebutton && skip_1release) {
452 #ifdef debug_mouse
453 			printf ("skipping 1 mouse release event\n");
454 #endif
455 			skipmouse = True;
456 			skip_1release = False;
457 		} else if (mouse_button != releasebutton && skip_1click) {
458 #ifdef debug_mouse
459 			printf ("skipping 1 mouse event\n");
460 #endif
461 			skipmouse = True;
462 			skip_1click = False;
463 			skip_1release = False;
464 		} else if (! window_focus) {
465 			/* should not be needed anymore */
466 #ifdef debug_mouse
467 			printf ("skipping mouse event while focus out\n");
468 #endif
469 			skipmouse = True;
470 		}
471 	}
472 
473 	if (skipmouse) {
474 		return readcharacter_mapping (map_keyboard, return_unicode);
475 	} else {
476 		/* WINCH exception isn't passing by here... */
477 #ifdef debug_mouse
478 		if (command (unichar) == MOUSEfunction) {
479 			if (mouse_button == releasebutton) {
480 				printf ("passing mouse release event\n");
481 			} else {
482 				printf ("passing mouse event\n");
483 			}
484 		}
485 #endif
486 		return FUNcmd;
487 	}
488   }
489 
490   if (utf8_input || queue_mode_mapped) {
491 	if ((unichar & 0x80) == 0x00) {
492 		utfcount = 1;
493 	} else if ((unichar & 0xE0) == 0xC0) {
494 		utfcount = 2;
495 		unichar = unichar & 0x1F;
496 	} else if ((unichar & 0xF0) == 0xE0) {
497 		utfcount = 3;
498 		unichar = unichar & 0x0F;
499 	} else if ((unichar & 0xF8) == 0xF0) {
500 		utfcount = 4;
501 		unichar = unichar & 0x07;
502 	} else if ((unichar & 0xFC) == 0xF8) {
503 		utfcount = 5;
504 		unichar = unichar & 0x03;
505 	} else if ((unichar & 0xFE) == 0xFC) {
506 		utfcount = 6;
507 		unichar = unichar & 0x01;
508 	} else /* illegal UTF-8 code */ {
509 		return unichar;
510 	}
511 	while (utfcount > 1) {
512 		unichar = (unichar << 6) | (readchar_nokeymap () & 0x3F);
513 		utfcount --;
514 	}
515 	if (! return_unicode && (cjk_text || mapped_text)) {
516 		return encodedchar (unichar);
517 	} else {
518 		return unichar;
519 	}
520   } else if (cjk_term && multichar (unichar)) {
521 	if (unichar == 0x8E && text_encoding_tag == 'C') {
522 		unichar = (unichar << 24)
523 			| (readchar_nokeymap () << 16)
524 			| (readchar_nokeymap () << 8)
525 			| readchar_nokeymap ();
526 	} else if (unichar == 0x8F && (text_encoding_tag == 'J' || text_encoding_tag == 'X')) {
527 		unichar = (unichar << 16)
528 			| (readchar_nokeymap () << 8)
529 			| readchar_nokeymap ();
530 	} else {
531 		int byte2 = readchar_nokeymap ();
532 		if (text_encoding_tag == 'G' && '0' <= byte2 && byte2 <= '9') {
533 			unichar = (unichar << 24)
534 				| (byte2 << 16)
535 				| (readchar_nokeymap () << 8)
536 				| readchar_nokeymap ();
537 		} else {
538 			unichar = (unichar << 8) | byte2;
539 		}
540 	}
541 	if (return_unicode || utf8_text) {
542 		unichar = lookup_encodedchar (unichar);
543 	}
544 	return unichar;
545   } else {
546 	if (mapped_term) {
547 		if (! return_unicode && (cjk_text || mapped_text) && ! remapping_chars ()) {
548 #ifdef debug_mapped_keyboard
549 			printf ("rc_m mapped (ret_u %d) -> %04X\n", return_unicode, unichar);
550 #endif
551 			return unichar;
552 		} else if (ascii_screen) {
553 			/* skip validity check to allow Latin-1 input
554 			   if ASCII screen is set (reason may be just
555 			   missing display capability)
556 			 */
557 		} else {
558 #ifdef debug_mapped_keyboard
559 			printf ("rc_m mapped (ret_u %d) -> %04X -> %04X ...\n", return_unicode, unichar, lookup_mappedtermchar (unichar));
560 #endif
561 			unichar = lookup_mappedtermchar (unichar);
562 			if (no_unichar (unichar)) {
563 #ifdef debug_mapped_keyboard
564 				printf ("rc_m mapped -> CHAR_INVALID\n");
565 #endif
566 				return CHAR_INVALID;
567 			}
568 		}
569 	}
570 
571 	if (! return_unicode && (cjk_text || mapped_text)) {
572 #ifdef debug_mapped_keyboard
573 		printf ("rc_m -> %04X -> %04X\n", unichar, encodedchar (unichar));
574 #endif
575 		return encodedchar (unichar);
576 	} else {
577 #ifdef debug_mapped_keyboard
578 		printf ("rc_m -> %04X\n", unichar);
579 #endif
580 		return unichar;
581 	}
582   }
583 }
584 
585 /*
586    readcharacter () reads one character
587    keyboard mapping is suppressed
588  */
589 unsigned long
readcharacter()590 readcharacter ()
591 {
592   return readcharacter_mapping (False, False);
593 }
594 
595 /*
596    readcharacter_mapped () reads one character
597    keyboard mapping is enabled
598  */
599 unsigned long
readcharacter_mapped()600 readcharacter_mapped ()
601 {
602   return readcharacter_mapping (True, False);
603 }
604 
605 /*
606    readcharacter_unicode () reads one Unicode character
607    keyboard mapping is suppressed
608  */
609 unsigned long
readcharacter_unicode()610 readcharacter_unicode ()
611 {
612   return readcharacter_mapping (False, True);
613 }
614 
615 /*
616    readcharacter_unicode_mapped () reads one Unicode character
617    keyboard mapping is enabled
618  */
619 unsigned long
readcharacter_unicode_mapped()620 readcharacter_unicode_mapped ()
621 {
622   return readcharacter_mapping (True, True);
623 }
624 
625 /*
626    readcharacter_allbuttons always reports mouse button release
627    and also reports window size change as function RDwin
628  */
629 unsigned long
readcharacter_allbuttons(map_keyboard)630 readcharacter_allbuttons (map_keyboard)
631   FLAG map_keyboard;
632 {
633   unsigned long c;
634   int prev_report_winchg = report_winchg;
635 
636   report_winchg = 1;
637 
638 #ifdef debug_mouse
639   printf ("readchar_allbuttons: report_release = True\n");
640 #endif
641   report_release = True;
642 
643   c = readcharacter_mapping (map_keyboard, True);
644 
645   report_winchg = prev_report_winchg;
646 
647   return c;
648 }
649 
650 
651 /*======================================================================*\
652 |*			Mouse input					*|
653 \*======================================================================*/
654 
655 #ifdef debug_mouse
656 
657 extern void do_trace_mouse _((char * tag));
658 
659 void
do_trace_mouse(tag)660 do_trace_mouse (tag)
661   char * tag;
662 {
663   static char * button_name [] = {
664 	"releasebutton",
665 	"leftbutton",
666 	"middlebutton",
667 	"rightbutton",
668 	"movebutton",
669 	"wheelup",
670 	"wheeldown"};
671 
672   printf ("[%s] ", tag);
673   printf ("%X ", mouse_shift);
674   if (mouse_button != releasebutton) {
675 	printf ("%s", button_name [mouse_button]);
676   } else {
677 	printf ("release (%s)", button_name [mouse_prevbutton]);
678   }
679   printf (" @ %d:%d (%d:%d)\n", mouse_ypos, mouse_xpos, mouse_prevypos, mouse_prevxpos);
680 }
681 
682 #endif
683 
684 static
685 void
notice_previous_click()686 notice_previous_click ()
687 {
688   /* remember previous mouse click */
689   if (mouse_button == leftbutton || mouse_button == rightbutton || mouse_button == middlebutton) {
690 	mouse_prevbutton = mouse_button;
691 	mouse_prevxpos = mouse_xpos;
692 	mouse_prevypos = mouse_ypos;
693 	mouse_buttons_pressed ++;
694   }
695 }
696 
697 static
698 void
fix_mouse_release_event()699 fix_mouse_release_event ()
700 {
701   /* workaround for incorrect mouse wheel escape sequences */
702   if (mouse_button == releasebutton) {
703 	if (mouse_buttons_pressed > 0) {
704 		mouse_buttons_pressed --;
705 	} else {
706 		/* fix the event report */
707 		mouse_button = movebutton;
708 	}
709   }
710 }
711 
712 /*
713  * DIRECT...getxy () reads in the information part of a cursor escape sequence
714  */
715 static
716 int
DIRECTxtermgetbut()717 DIRECTxtermgetbut ()
718 {
719   int but = _readchar_nokeymap ();
720   if (but == quit_char) {
721 	quit = True;
722 	return 0;
723   }
724   if (use_mouse_extended) {
725 	if ((but & 0xE0) == 0xC0) {
726 		but &= 0x1F;
727 		but = (but << 6) | (_readchar_nokeymap () & 0x3F);
728 	}
729   }
730   return but;
731 }
732 
733 static
734 int
DIRECTxtermgetpos()735 DIRECTxtermgetpos ()
736 {
737   int pos = _readchar_nokeymap ();
738   if (pos == quit_char) {
739 	quit = True;
740 	return 0;
741   }
742   if (use_mouse_extended) {
743 	if ((pos & 0xE0) == 0xC0) {
744 		pos &= 0x1F;
745 		pos = (pos << 6) | (_readchar_nokeymap () & 0x3F);
746 	}
747 	if (pos == 0) {
748 		pos = 0x800;	/* out of range */
749 	}
750   } else if (pos == 0) {
751 	pos = 256;	/* out of range */
752   }
753   return pos - 33;
754 }
755 
756 static
757 void
get_mouse_button(button)758 get_mouse_button (button)
759   unsigned int button;
760 {
761   mouse_shift = button & 0x1C;
762   if (button & 32) {
763 	mouse_button = movebutton;
764   } else if (button & 64) {
765 	button &= 0x03;
766 	if (button == 0x00) {
767 		mouse_button = wheelup;
768 	} else {
769 		mouse_button = wheeldown;
770 	}
771   } else {
772 	button &= 0x03;
773 	if (button == 0x00) {
774 		mouse_button = leftbutton;
775 	} else if (button == 0x01) {
776 		mouse_button = middlebutton;
777 	} else if (button == 0x02) {
778 		mouse_button = rightbutton;
779 	} else {
780 		mouse_button = releasebutton;
781 	}
782   }
783 }
784 
785 static
786 void
DIRECTxtermgetxy(code)787 DIRECTxtermgetxy (code)
788   char code;	/* 'M' for normal mouse report, 't'/'T' for tracking */
789 {
790   character button;
791 
792   notice_previous_click ();
793 
794   if (code == 't') {
795 	mouse_button = releasebutton;
796   } else if (code == 'T') {
797 	/* could be Siemens 97801/97808 page down ... !?! */
798 	button = _readchar_nokeymap ();
799 	button = _readchar_nokeymap ();
800 	button = _readchar_nokeymap ();
801 	button = _readchar_nokeymap ();
802 	mouse_button = releasebutton;
803   } else {	/* code == 'M' */
804 	if (xterm_version >= 268) {
805 		button = DIRECTxtermgetbut ();
806 	} else {
807 		button = _readchar_nokeymap ();
808 		if (button == quit_char) {
809 			quit = True;
810 		}
811 	}
812 
813 	if (bidi_screen && mintty_version == 0 && button == '$') {
814 		/* fix mlterm quirk for mouse wheel scroll down */
815 		button = 'a';
816 		button = '#';
817 	}
818 	get_mouse_button (button - 32);
819   }
820 
821   fix_mouse_release_event ();
822 
823   mouse_xpos = DIRECTxtermgetpos ();
824   mouse_ypos = DIRECTxtermgetpos () - MENU;
825 
826 #ifdef debug_mouse
827   printf ("mouse %c: ", code);
828   trace_mouse ("DIRECTxtermgetxy");
829 #endif
830 
831 #if defined (unix) || defined (vms)
832   if (use_mouse_button_event_tracking && mouse_button == releasebutton) {
833 	mouse_button_event_mode (False);
834   }
835 #endif
836 }
837 
838 static
839 void
DIRECTsgrgetxy()840 DIRECTsgrgetxy ()
841 {
842   notice_previous_click ();
843 
844   if (ansi_fini == 'm') {
845 	ansi_param [0] |= 0x3;	/* release button */
846   }
847   get_mouse_button (ansi_param [0]);
848 
849   fix_mouse_release_event ();
850 
851   mouse_ypos = ansi_param [2] - 1 - MENU;
852   mouse_xpos = ansi_param [1] - 1;
853 }
854 
855 static
856 void
DIRECTurxvtgetxy()857 DIRECTurxvtgetxy ()
858 {
859   notice_previous_click ();
860 
861   get_mouse_button (ansi_param [0] - 32);
862 
863   fix_mouse_release_event ();
864 
865   mouse_ypos = ansi_param [2] - 1 - MENU;
866   mouse_xpos = ansi_param [1] - 1;
867 }
868 
869 static
870 void
DIRECTcrttoolgetxy()871 DIRECTcrttoolgetxy ()
872 {
873   character c;
874   int xpos;
875   int ypos;
876 
877   /* fix crttool settings */
878   use_ascii_graphics = True;
879   menu_border_style = 'r';
880   use_mouse_release = False;
881 
882   notice_previous_click ();
883 
884   c = get_digits (& ypos); /* c should be ';' */
885   c = get_digits (& xpos);
886   if (c == 'l') {
887 	mouse_button = leftbutton;
888   } else if (c == 'm') {
889 	mouse_button = middlebutton;
890   } else if (c == 'r') {
891 	mouse_button = rightbutton;
892   } else {
893 	mouse_button = releasebutton;
894   }
895 
896   fix_mouse_release_event ();
897 
898   mouse_ypos = ypos - 1 - MENU;
899   mouse_xpos = xpos - 1;
900 }
901 
902 static
903 void
DIRECTvtlocatorgetxy()904 DIRECTvtlocatorgetxy ()
905 {
906   notice_previous_click ();
907 
908   if (ansi_param [0] == 2) {
909 	mouse_button = leftbutton;
910   } else if (ansi_param [0] == 4) {
911 	mouse_button = middlebutton;
912   } else if (ansi_param [0] == 6) {
913 	mouse_button = rightbutton;
914   } else if (ansi_param [0] == 9) {
915 	mouse_button = wheelup;
916   } else if (ansi_param [0] == 11) {
917 	mouse_button = wheeldown;
918   } else {
919 	mouse_button = releasebutton;
920   }
921 
922   fix_mouse_release_event ();
923 
924   mouse_ypos = ansi_param [2] - 1 - MENU;
925   mouse_xpos = ansi_param [3] - 1;
926 }
927 
928 /*
929  * DIRECT... () reads in a direct cursor movement input sequence.
930  * Then it either performs a direct function (move/copy/paste) or
931  * invokes the menu functions.
932  * Is no longer called as this is already handled in _readchar ().
933  */
934 void
DIRECTxterm()935 DIRECTxterm ()
936 {
937 #ifdef debug_mouse
938   printf ("DIRECTxterm\n");
939 #endif
940   DIRECTxtermgetxy ('M');
941   MOUSEfunction ();
942 }
943 
944 void
TRACKxterm()945 TRACKxterm ()
946 {
947 #ifdef debug_mouse
948   printf ("TRACKxterm\n");
949 #endif
950   DIRECTxtermgetxy ('t');
951   MOUSEfunction ();
952 }
953 
954 void
TRACKxtermT()955 TRACKxtermT ()
956 {
957 #ifdef debug_mouse
958   printf ("TRACKxtermT\n");
959 #endif
960   DIRECTxtermgetxy ('T');
961   MOUSEfunction ();
962 }
963 
964 void
DIRECTcrttool()965 DIRECTcrttool ()
966 {
967   DIRECTcrttoolgetxy ();
968   MOUSEfunction ();
969 }
970 
971 void
DIRECTvtlocator()972 DIRECTvtlocator ()
973 {
974   DIRECTvtlocatorgetxy ();
975   MOUSEfunction ();
976 }
977 
978 
979 #ifdef CURSES
980 #ifdef KEY_MOUSE
981 
982 #ifdef __PDCURSES__
983 
984 /*
985  * CURSgetxy () reads in the information of a mouse event
986  */
987 static
988 void
CURSgetxy()989 CURSgetxy ()
990 {
991 # define mouse_state Mouse_status.changes
992 # define mouse_x MOUSE_X_POS
993 # define mouse_y MOUSE_Y_POS
994 
995   int button = 0;
996 
997   notice_previous_click ();
998 
999   request_mouse_pos ();
1000 
1001   if (BUTTON_CHANGED (1)) {
1002 	button = 1;
1003   } else if (BUTTON_CHANGED (2)) {
1004 	button = 2;
1005   } else if (BUTTON_CHANGED (3)) {
1006 	button = 3;
1007   }
1008 
1009 #ifdef BUTTON_SHIFT
1010   mouse_shift = (BUTTON_STATUS (button) & BUTTON_MODIFIER_MASK) == BUTTON_SHIFT;
1011 #else
1012   mouse_shift = 0;
1013 #endif
1014 
1015   if ((BUTTON_STATUS (button) & BUTTON_ACTION_MASK) == BUTTON_PRESSED) {
1016 	if (button == 1) {
1017 		mouse_button = leftbutton;
1018 	} else if (button == 2) {
1019 		mouse_button = middlebutton;
1020 	} else if (button == 3) {
1021 		mouse_button = rightbutton;
1022 	} else {
1023 		mouse_button = releasebutton;
1024 	}
1025   } else {
1026 	mouse_button = releasebutton;
1027   }
1028 
1029   fix_mouse_release_event ();
1030 
1031   mouse_xpos = mouse_x;
1032   mouse_ypos = mouse_y - MENU;
1033 }
1034 
1035 # else
1036 
1037 static
1038 void
CURSgetxy()1039 CURSgetxy ()
1040 {
1041 #ifdef NCURSES_VERSION
1042   MEVENT mouse_info;
1043 # define mouse_state mouse_info.bstate
1044 # define mouse_x mouse_info.x
1045 # define mouse_y mouse_info.y
1046 #else
1047   unsigned long mouse_state;
1048 # define mouse_x Mouse_status.x
1049 # define mouse_y Mouse_status.y
1050 #endif
1051 
1052   notice_previous_click ();
1053 
1054 #ifdef NCURSES_VERSION
1055   getmouse (& mouse_info);
1056 #else
1057   mouse_state = getmouse ();
1058 #endif
1059 
1060 #ifdef BUTTON_SHIFT
1061   mouse_shift = mouse_state & BUTTON_SHIFT;
1062 #else
1063   mouse_shift = 0;
1064 #endif
1065 
1066   if (mouse_state & BUTTON1_CLICKED) {
1067 	mouse_button = leftbutton;
1068   } else if (mouse_state & BUTTON2_CLICKED) {
1069 	mouse_button = middlebutton;
1070   } else if (mouse_state & BUTTON3_CLICKED) {
1071 	mouse_button = rightbutton;
1072   } else {
1073 	mouse_button = releasebutton;
1074   }
1075 
1076   fix_mouse_release_event ();
1077 
1078   mouse_xpos = mouse_x - 1;
1079   mouse_ypos = mouse_y - 1 - MENU;
1080 }
1081 
1082 #endif
1083 
1084 #endif
1085 #endif
1086 
1087 
1088 /*======================================================================*\
1089 |*			Character input					*|
1090 \*======================================================================*/
1091 
1092 /* max. length of function key sequence to be detected
1093    (depending on the fkeymap table, approx. 7),
1094    or of keyboard mapping sequence plus potential mapping rest
1095 */
1096 #define MAXCODELEN 33
1097 
1098 /*
1099  * queue collects the keys of an Escape sequence typed in until the
1100  * sequence can be detected or rejected.
1101  * If the queue is not empty, queue [0] contains the character next
1102  * to be delivered by _readchar () (it's not a ring buffer).
1103  * The queue contents are always terminated by a '\0', so queue can also
1104  * be taken as a character string.
1105  */
1106 static character queue [MAXCODELEN + 1];
1107 static character * endp = queue;
1108 static character ctrl_queue [MAXCODELEN + 1];
1109 static character * endcp = ctrl_queue;
1110 static character raw_queue [MAXCODELEN + 1];
1111 static int rqi = 0;
1112 
1113 static
1114 int
get1byte()1115 get1byte ()
1116 {
1117   int c = read1byte ();
1118   if (rqi < MAXCODELEN) {
1119 	raw_queue [rqi ++] = c;
1120 	raw_queue [rqi] = '\0';
1121   }
1122   return c;
1123 }
1124 
1125 #ifdef not_used
1126 static
1127 int
q_empty()1128 q_empty ()
1129 {
1130   return endp == queue ? 1 : 0;
1131 }
1132 #endif
1133 
1134 static
1135 int
q_notfull()1136 q_notfull ()
1137 {
1138   return endp - queue == MAXCODELEN ? 0 : 1;
1139 }
1140 
1141 static
1142 void
raw_q_clear()1143 raw_q_clear ()
1144 {
1145   rqi = 0;
1146 }
1147 
1148 static
1149 void
q_clear()1150 q_clear ()
1151 {
1152   endp = queue;
1153   endcp = ctrl_queue;
1154   rqi = 0;
1155 }
1156 
1157 static
1158 int
q_len()1159 q_len ()
1160 {
1161   return endp - queue;
1162 }
1163 
1164 static
1165 void
q_put(c)1166 q_put (c)
1167   character c;
1168 /* queue must not be full prior to this call! */
1169 {
1170   * endp = c;
1171   * ++ endp = '\0';
1172   if (c == '\0') {
1173 	* endcp = '@';
1174   } else {
1175 	* endcp = c;
1176   }
1177   * ++ endcp = '\0';
1178 }
1179 
1180 /*
1181 static
1182 character
1183 q_unput ()
1184 {
1185   character c;
1186   if (q_len () == 0) {
1187 	return '\0';
1188   } else {
1189 	endp --;
1190 	endcp --;
1191 	c = * endp;
1192 	* endp = '\0';
1193 	* endcp = '\0';
1194 	return c;
1195   }
1196 }
1197 */
1198 
1199 static
1200 character
q_get()1201 q_get ()
1202 {
1203   character c;
1204   register character * pd;
1205   register character * ps;
1206 
1207   c = * queue;
1208   pd = queue;
1209   ps = pd + 1;
1210   while (ps <= endp) {
1211 	* pd ++ = * ps ++;
1212   }
1213   if (endp > queue) {
1214 	endp --;
1215 	endcp --;
1216   }
1217 
1218 #define dont_debug_queue_delivery
1219 #ifdef debug_queue_delivery
1220   printf ("%02X\n", c);
1221 #endif
1222 
1223   return c;
1224 }
1225 
1226 
1227 #ifndef msdos
1228 
1229 /*
1230  * Look up key sequence in fkeymap table.
1231  * if matchmode == 0:
1232  * findkey (str) >=  0: escape sequence found
1233  *				(str == fkeymap [findkey (str)].fk)
1234  *			keyproc = fkeymap [i].fp (side effect)
1235  *		 == -1: escape sequence prefix recognised
1236  *				(str is prefix of some entry in fkeymap)
1237  *		 == -2: escape sequence not found
1238  *				(str is not contained in fkeymap)
1239  * * found == index of exact match if found
1240  * if matchmode == 1 (not used):
1241  * return -1 if any prefix detected (even if other exact match found)
1242  * if matchmode == 2 (not used):
1243  * don't return -1, only report exact or no match
1244  */
1245 static
1246 int
findkeyin(str,fkeymap,matchmode,found)1247 findkeyin (str, fkeymap, matchmode, found)
1248   char * str;
1249   struct fkeyentry * fkeymap;
1250   int matchmode;
1251   int * found;
1252 {
1253   int lastmatch = 0;	/* last index with string matching prefix */
1254   register int i;
1255   int ret = -2;
1256 
1257   * found = -1;
1258 
1259   if (fkeymap [0].fk == NIL_PTR) {
1260 	return ret;
1261   }
1262 
1263   i = lastmatch;
1264   do {
1265 	char * strpoi = str;
1266 	char * mappoi = fkeymap [i].fk;
1267 	do {
1268 		/* compare str with map entry */
1269 		if (* strpoi != * mappoi) {
1270 			break;
1271 		}
1272 		if (* strpoi) {
1273 			strpoi ++;
1274 			mappoi ++;
1275 		}
1276 	} while (* strpoi);
1277 
1278 /*	if (strncmp (str, fkeymap [i].fk, strlen (str)) == 0) {*/
1279 	if (* strpoi == '\0') {
1280 		/* str is prefix of current entry */
1281 		lastmatch = i;
1282 /*		if (strlen (str) == strlen (fkeymap [i].fk)) {*/
1283 		if (* mappoi == '\0') {
1284 			/* str is equal to current entry */
1285 			* found = i;
1286 			keyproc = fkeymap [i].fp;
1287 			if (! keyproc) {
1288 				keyproc = I;
1289 			}
1290 			fkeyshift = fkeymap [i].fkeyshift;
1291 			if (matchmode == 1) {
1292 				/* return index unless other prefix
1293 				   was or will be found */
1294 				if (ret == -2) {
1295 					ret = i;
1296 				}
1297 			} else {
1298 				return i;
1299 			}
1300 		} else {
1301 			/* str is partial prefix of current entry */
1302 			if (matchmode == 1) {
1303 				/* return -1 but continue to search
1304 				   for exact match */
1305 				ret = -1;
1306 			} else if (matchmode != 2) {
1307 				return -1;
1308 			} else {
1309 			}
1310 		}
1311 	}
1312 	++ i;
1313 	if (fkeymap [i].fk == NIL_PTR) {
1314 		i = 0;
1315 		return ret;
1316 	}
1317   } while (i != lastmatch);
1318 
1319   return ret;
1320 }
1321 
1322 static
1323 int
findkey(str)1324 findkey (str)
1325   char * str;
1326 {
1327   int dummy;
1328   int res;
1329 
1330   res = findkeyin (str, fkeymap_spec, 0, & dummy);
1331 #ifdef debug_findkey
1332   printf ("<^[%s> _specific [%d]\n", str + 1, res);
1333 #endif
1334 
1335   if (res != -2) {
1336 	return res;
1337   }
1338 
1339   res = findkeyin (str, fkeymap, 0, & dummy);
1340 #ifdef debug_findkey
1341   printf ("<^[%s> _deftable [%d]\n", str + 1, res);
1342 #endif
1343 
1344   if (res != -2) {
1345 	return res;
1346   }
1347 
1348 #ifdef TERMINFO
1349   res = findkeyin (str, fkeymap_terminfo, 0, & dummy);
1350 # ifdef debug_findkey
1351   printf ("<^[%s> _terminfo [%d]\n", str + 1, res);
1352 # endif
1353 #endif
1354 
1355   return res;
1356 }
1357 
1358 #endif	/* #ifndef msdos */
1359 
1360 
1361 #ifdef CURSES
1362 # ifdef vms
1363 typedef unsigned int chtype;
1364 # endif
1365 
1366 chtype key;
1367 
1368 extern int curs_readchar _((void));
1369 
1370 static
1371 void
showfkey()1372 showfkey ()
1373 {
1374   build_string (text_buffer, "Curses function key entered: %03X / %04o", (int) key, (int) key);
1375   status_msg (text_buffer);
1376 }
1377 
1378 
1379 /*
1380  * Read a character, ignoring uninterpreted key strokes (SHIFT etc.)
1381  * also handles resize events
1382  */
1383 int
curs_readchar()1384 curs_readchar ()
1385 {
1386   unsigned long keycode;
1387   keycode = __readchar ();
1388 #ifdef vms
1389   if (keycode >= 0x100) {
1390 	printf ("readchar: vms curses key %03X\n", keycode); sleep (1);
1391   }
1392 #else
1393   while (keycode >= KEY_MIN) {
1394 	switch (keycode) {
1395 #ifdef KEY_RESIZE
1396 	case KEY_RESIZE:
1397 		printf ("curses resize key received \n"); sleep (1);
1398 		keyproc = showfkey;
1399 		return FUNcmd;
1400 #endif
1401 #ifdef KEY_SHIFT_L
1402 	case KEY_SHIFT_L:
1403 	case KEY_SHIFT_R:
1404 	case KEY_CONTROL_L:
1405 	case KEY_CONTROL_R:
1406 	case KEY_ALT_L:
1407 	case KEY_ALT_R:
1408 		break;
1409 #endif
1410 	default:
1411 		return keycode;
1412 	}
1413 	keycode = __readchar ();
1414   }
1415 #endif
1416 
1417   return keycode;
1418 }
1419 
1420 /*
1421  * Mapping KEY_ code (curses) -> mined function
1422  */
1423 struct {
1424 	chtype keycode;
1425 	voidfunc func;
1426 	unsigned char fkeyshift;
1427 } cursfunc [] = {
1428 #ifndef vms
1429 	{KEY_F(1), F1},
1430 	{KEY_F(2), F2},
1431 	{KEY_F(3), F3},
1432 	{KEY_F(4), F4},
1433 	{KEY_F(5), F5},
1434 	{KEY_F(6), F6},
1435 	{KEY_F(7), F7},
1436 	{KEY_F(8), F8},
1437 	{KEY_F(9), F9},
1438 	{KEY_F(10), F10},
1439 	{KEY_F(11), F11},
1440 	{KEY_F(12), F12},
1441 	{KEY_IC, INSkey},
1442 	{KEY_DC, DELkey},
1443 	{KEY_HOME, HOMEkey},
1444 	{KEY_END, ENDkey},
1445 	{KEY_PPAGE, PGUPkey},
1446 	{KEY_NPAGE, PGDNkey},
1447 	{KEY_UP, UPkey},
1448 	{KEY_DOWN, DNkey},
1449 	{KEY_LEFT, LFkey},
1450 	{KEY_RIGHT, RTkey},
1451 	{KEY_B2, HOP},
1452 	{KEY_A1, HOMEkey},
1453 	{KEY_A3, PGUPkey},
1454 	{KEY_C1, ENDkey},
1455 	{KEY_C3, PGDNkey},
1456 #endif
1457 #ifdef KEY_A2
1458 	{KEY_A2, UPkey},
1459 #endif
1460 #ifdef KEY_C2
1461 	{KEY_C2, DNkey},
1462 #endif
1463 #ifdef KEY_B1
1464 	{KEY_B1, LFkey},
1465 #endif
1466 #ifdef KEY_B3
1467 	{KEY_B3, RTkey},
1468 #endif
1469 	{0x1BF, BLINEORUP},
1470 	{0x1C0, ELINEORDN},
1471 
1472 #ifdef PAD0
1473 	{PAD0, PASTE},
1474 #endif
1475 #ifdef __PDCURSES__
1476 	{PADSLASH, I},
1477 	{PADSTAR, I},
1478 	{PADMINUS, I},
1479 	{PADPLUS, I},
1480 	{PADSTOP, CUT},
1481 	{PADENTER, SNL},
1482 	{ALT_F, FILEMENU},
1483 	{ALT_E, EDITMENU},
1484 	{ALT_S, SEARCHMENU},
1485 	{ALT_P, PARAMENU},
1486 	{ALT_O, OPTIONSMENU},
1487 #endif
1488 
1489 	{0}
1490 };
1491 
1492 /*
1493  * Look up mined function by curses key code
1494  * lookup_curskey (str) >=  0: keycode == cursfunc [lookup_curskey (str)].fk
1495  *			== -1: keycode is not contained in mapping table
1496  */
1497 static
1498 voidfunc
lookup_curskey(keycode)1499 lookup_curskey (keycode)
1500   chtype keycode;
1501 {
1502   register int i;
1503 
1504   i = 0;
1505   while (cursfunc [i].keycode != 0 && cursfunc [i].keycode != keycode) {
1506 	i ++;
1507   }
1508   if (cursfunc [i].keycode == 0) {
1509 	return showfkey;
1510   } else {
1511 	keyshift |= cursfunc [i].fkeyshift;
1512 	return cursfunc [i].func;
1513   }
1514 }
1515 
1516 #endif
1517 
1518 
1519 /*
1520  * Functions to read a character from terminal.
1521    If _readchar () detects a function key sequence (according to the
1522    table fkeymap), FUNcmd is returned, and the associated function is
1523    stored in the variable keyproc.
1524    Keyboard mapping is applied.
1525  */
1526 
1527 unsigned long
_readchar_nokeymap()1528 _readchar_nokeymap ()
1529 {
1530   unsigned long c;
1531   int prev_dont_suppress_keymap = dont_suppress_keymap;
1532 
1533   dont_suppress_keymap = 0;
1534   c = _readchar ();
1535   dont_suppress_keymap = prev_dont_suppress_keymap;
1536 
1537   return c;
1538 }
1539 
1540 
1541 #define dont_debug_readbyte
1542 
1543 #define dont_debug_terminal_response
1544 #ifdef debug_terminal_response
1545 #define trace_terminal_response(what)	if (debug_tag) printf ("[%s (%d)] %s\n", debug_tag, msec, what);
1546 #else
1547 #define trace_terminal_response(what)
1548 #endif
1549 
1550 
1551 static int choose_char _((char *));
1552 
1553 static character rest_queue [MAXCODELEN + 1];
1554 static FLAG have_rest_queue = False;
1555 
1556 static
1557 void
putback_rest(rest)1558 putback_rest (rest)
1559   char * rest;
1560 {
1561   char old_rest_queue [MAXCODELEN + 1];
1562 #ifdef debug_readbyte
1563   printf ("putback_rest <%s>\n", rest);
1564 #endif
1565 
1566   if (! streq (rest, " ")) {
1567 	if (have_rest_queue) {
1568 		/**
1569 		   overdraft characters to be mapped are
1570 		   put back into rest_queue
1571 		   to be considered for subsequent mapping
1572 			-> Hiragana nihongo
1573 			-> Hiragana nyi
1574 			-> test abcde
1575 		 */
1576 		strcpy (old_rest_queue, (char *) rest_queue);
1577 	} else {
1578 		old_rest_queue [0] = '\0';
1579 	}
1580 	strcpy ((char *) rest_queue, rest);
1581 	strcat ((char *) rest_queue, old_rest_queue);
1582 	have_rest_queue = True;
1583   }
1584 }
1585 
1586 /* read 1 byte from queue; for curses, however, function
1587    key indications must be passed on which are longer than 8 bits
1588  */
1589 int
read1byte()1590 read1byte ()
1591 {
1592   if (have_rest_queue) {
1593 	character * cr = rest_queue;
1594 	character ch = * rest_queue;
1595 	while (* (cr + 1) != '\0') {
1596 		* cr = * (cr + 1);
1597 		cr ++;
1598 	}
1599 	* cr = '\0';
1600 	if (* rest_queue == '\0') {
1601 		have_rest_queue = False;
1602 	}
1603 #ifdef debug_readbyte
1604 	printf ("read byte %02X from rest queue\n", ch);
1605 #endif
1606 	return ch;
1607   } else {
1608 	int ch;
1609 #ifdef CURSES
1610 	ch = curs_readchar ();
1611 #else
1612 #ifdef debug_readbyte
1613 	printf ("reading byte from io (report_winchg %d)\n", report_winchg);
1614 #endif
1615 	if (report_winchg) {
1616 		ch = __readchar_report_winchg ();
1617 	} else {
1618 		ch = __readchar ();
1619 	}
1620 #endif
1621 #ifdef debug_readbyte
1622 	printf ("read byte %02X from io\n", ch);
1623 #endif
1624 	return ch;
1625   }
1626 }
1627 
1628 
1629 static
1630 int
bytereadyafter(msec,debug_tag)1631 bytereadyafter (msec, debug_tag)
1632   int msec;
1633   char * debug_tag;
1634 {
1635   if (have_rest_queue) {
1636 	trace_terminal_response ("from rest queue");
1637 	return 1;
1638   } else {
1639 	if (inputreadyafter (msec) > 0) {
1640 		trace_terminal_response ("response");
1641 		return 1;
1642 	} else {
1643 		trace_terminal_response ("timeout");
1644 		return 0;
1645 	}
1646   }
1647 }
1648 
1649 /*
1650  * Is a character available within a specified number of milliseconds ?
1651  */
1652 int
char_ready_within(msec,debug_tag)1653 char_ready_within (msec, debug_tag)
1654   int msec;
1655   char * debug_tag;
1656 {
1657   if (q_len () > 0) {
1658 	trace_terminal_response ("from queue");
1659 	return 1;
1660   } else {
1661 	return bytereadyafter (msec, debug_tag);
1662   }
1663 }
1664 
1665 
1666 #ifndef msdos
1667 #define radical_stroke
1668 #endif
1669 
1670 
1671 #ifdef radical_stroke
1672 static menuitemtype radicalsmenu [] = {
1673 	/* 1 stroke radicals */
1674 	{"①.1:一 2:丨 3:丶 4:丿乀乁 5:乙乚乛 6:亅", dummyfunc, ""},
1675 	/* 2 strokes radicals */
1676 	{"②.7:二 8:亠 9:人亻 10:儿 11:入 12:八 13:冂 14:冖", dummyfunc, ""},
1677 	{"②.15:冫 16:几 17:凵 18:刀刁刂 19:力 20:勹 21:匕", dummyfunc, ""},
1678 	{"②.22:匚 23:匸 24:十 25:卜 26:卩 27:厂 28:厶 29:又", dummyfunc, ""},
1679 	/* 3 strokes radicals */
1680 	{"③.30:口 31:囗 32:土 33:士 34:夂 35:夊 36:夕 37:大夨 38:女 39:子孑孒孓", dummyfunc, ""},
1681 	{"③.40:宀 41:寸 42:小 43:尢尣 44:尸 45:屮 46:山 47:巛巜川 48:工 49:己已巳", dummyfunc, ""},
1682 	{"③.50:巾 51:干 52:乡幺 53:广 54:廴 55:廾 56:弋 57:弓 58:彐彑 59:彡 60:彳", dummyfunc, ""},
1683 	/* 4 strokes radicals */
1684 	{"④.61:心忄 62:戈 63:戶户戸 64:手扌才 65:支 66:攴攵 67:文 68:斗", dummyfunc, ""},
1685 	{"④.69:斤 70:方 71:无 72:日 73:曰 74:月 75:木朩 76:欠 77:止 78:歹 79:殳", dummyfunc, ""},
1686 	{"④.80:毋毌 81:比 82:毛 83:氏 84:气 85:水氵 86:火灬 87:爪爫 88:父 89:爻", dummyfunc, ""},
1687 	{"④.90:丬爿 91:片 92:牙㸦 93:牛牜 94:犬犭", dummyfunc, ""},
1688 	/* 5 strokes radicals */
1689 	{"⑤.95:玄 96:玉王 97:瓜 98:瓦 99:甘 100:生 101:用甩 102:田由甲申甴电", dummyfunc, ""},
1690 	{"⑤.103:疋 104:疒 105:癶 106:白 107:皮 108:皿 109:目", dummyfunc, ""},
1691 	{"⑤.110:矛 111:矢 112:石 113:示礻 114:禸 115:禾 116:穴 117:立", dummyfunc, ""},
1692 	/* 6 strokes radicals */
1693 	{"⑥.118:竹 119:米 120:糸糹纟 121:缶 122:网罒罓䍏 123:羊 124:羽 125:老耂考", dummyfunc, ""},
1694 	{"⑥.126:而 127:耒 128:耳 129:聿肀 130:肉 131:臣 132:自", dummyfunc, ""},
1695 	{"⑥.133:至 134:臼 135:舌 136:舛 137:舟 138:艮 139:色 140:艸艹䒑", dummyfunc, ""},
1696 	{"⑥.141:虍 142:虫 143:血 144:行 145:衣衤 146:襾西覀", dummyfunc, ""},
1697 	/* 7 strokes radicals */
1698 	{"⑦.147:見见 148:角 149:言訁讠 150:谷 151:豆 152:豕 153:豸", dummyfunc, ""},
1699 	{"⑦.154:貝贝 155:赤 156:走赱 157:足 158:身 159:車车 160:辛", dummyfunc, ""},
1700 	{"⑦.161:辰 162:辵辶 163:邑 164:酉 165:釆 166:里", dummyfunc, ""},
1701 	/* 8 strokes radicals */
1702 	{"⑧.167:金釒钅 168:長镸长 169:門门 170:阜阝", dummyfunc, ""},
1703 	{"⑧.171:隶 172:隹 173:雨 174:靑青 175:非", dummyfunc, ""},
1704 	/* 9 strokes radicals */
1705 	{"⑨.176:面靣 177:革 178:韋韦 179:韭 180:音 181:頁页", dummyfunc, ""},
1706 	{"⑨.182:風风 183:飛飞 184:食飠饣 185:首 186:香", dummyfunc, ""},
1707 	/* 10 strokes radicals */
1708 	{"⑩.187:馬马 188:骨 189:高髙 190:髟 191:鬥 192:鬯 193:鬲 194:鬼", dummyfunc, ""},
1709 	/* 11 strokes radicals */
1710 	{"⑪.195:魚鱼 196:鳥鸟 197:鹵 198:鹿 199:麥麦 200:麻", dummyfunc, ""},
1711 	/* 12 strokes radicals */
1712 	{"⑫.201:黃黄 202:黍 203:黑黒 204:黹", dummyfunc, ""},
1713 	/* 13 strokes radicals */
1714 	{"⑬.205:黽黾 206:鼎 207:鼓鼔 208:鼠鼡", dummyfunc, ""},
1715 	/* 14 strokes radicals */
1716 	{"⑭.209:鼻 210:齊齐", dummyfunc, ""},
1717 	/* 15 strokes radicals */
1718 	{"⑮.211:齒齿", dummyfunc, ""},
1719 	/* 16 strokes radicals */
1720 	{"⑯.212:龍龙 213:龜龟", dummyfunc, ""},
1721 	/* 17 strokes radical */
1722 	{"⑰.214:龠", dummyfunc, ""},
1723 };
1724 #endif
1725 
1726 
1727 #define dont_debug_kbesc
1728 #define dont_debug_kbansi
1729 #define dont_debug_kbmap
1730 
1731 static
1732 unsigned long
_readchar()1733 _readchar ()
1734 {
1735   unsigned long ch;
1736   char * choice;
1737   int choice_index;
1738   /* queue handling */
1739   int res;
1740   char * found;
1741   char * mapped;
1742   char * prev_found = NIL_PTR;
1743 
1744 
1745   if (escape_delay == 0 || keymap_delay == 0) {
1746 	char * env = envvar ("ESCDELAY");
1747 	if (env) {
1748 		(void) scan_int (env, & escape_delay);
1749 	}
1750 	if (escape_delay == 0) {
1751 		escape_delay = default_escape_delay;
1752 	}
1753 	env = envvar ("MAPDELAY");
1754 	if (env) {
1755 		(void) scan_int (env, & keymap_delay);
1756 	}
1757 	if (keymap_delay == 0) {
1758 		keymap_delay = default_keymap_delay;
1759 	}
1760   }
1761 
1762 
1763   if (q_len () > 0) {
1764 	return q_get ();
1765   }
1766   queue_mode_mapped = False;
1767   raw_q_clear ();
1768 
1769   keyshift = 0;
1770 #ifdef msdos
1771   mouse_shift = 0;
1772 #endif
1773 
1774 
1775 #ifdef radical_stroke
1776   /* plug-in specific input methods */
1777   if (allow_keymap && dont_suppress_keymap
1778 	&& streq (keyboard_mapping, "rs")
1779   ) {
1780 	int choice_col = x;
1781 	int choice_line = y + 1;
1782 	char radicalnumber [4];
1783 
1784 	choice_index = -1;
1785 
1786 	/* adjust menu position if too far down */
1787 	if (choice_line + arrlen (radicalsmenu) + 2 > YMAX) {
1788 		choice_line = y - arrlen (radicalsmenu) - 2;
1789 		if (choice_line < 0) {
1790 			choice_line = 0;
1791 		}
1792 	}
1793 
1794 	/* adjust menu position if on status line */
1795 	if (input_active) {
1796 		choice_line = YMAX - arrlen (radicalsmenu) - 2;
1797 		if (choice_line < 0) {
1798 			choice_line = 0;
1799 		}
1800 		choice_col = lpos;
1801 	}
1802 
1803 	/* try to get radical, then character, from user */
1804 	while (choice_index < 0) {
1805 		int radical = popup_menu (radicalsmenu, arrlen (radicalsmenu),
1806 					choice_col, choice_line,
1807 					"Select radical", False, False, "1234567890x");
1808 		if (radical < 0) {
1809 			/* revert to previous mapping (or none) */
1810 			toggleKEYMAP ();
1811 			set_cursor_xy ();
1812 			flush ();
1813 			choice_index = 0;	/* continue */
1814 		} else {
1815 			int radical_row = radical / 11;
1816 			int radical_col = radical % 11;
1817 			mapped = radicalsmenu [radical_row].itemname;
1818 			while (* mapped != '\0' &&
1819 			       (* mapped < '0' || * mapped > '9'
1820 			        || radical_col > 0))
1821 			{
1822 				if (* mapped == ':') {
1823 					radical_col --;
1824 				}
1825 				mapped ++;
1826 			}
1827 			found = radicalnumber;
1828 			while (* mapped >= '0' && * mapped <= '9') {
1829 				* found ++ = * mapped ++;
1830 			}
1831 			* found = '\0';
1832 			res = map_key (radicalnumber, 2, & found, & mapped);
1833 			if (res >= 0) {
1834 				/* first goto in my life and then
1835 				   such an exceptionally ugly one -
1836 				   but it works well just this way */
1837 				goto handle_mapped;
1838 			} else {
1839 				ring_bell ();
1840 			}
1841 		}
1842 	}
1843   }
1844 #endif
1845 
1846 
1847 #ifdef CURSES
1848 
1849   key = read1byte ();
1850 #ifdef vms
1851   if (key >= 0x100) {
1852 	printf ("_readchar: vms curses key %03X\n", key); sleep (1);
1853   }
1854 #else
1855   if (key >= KEY_MIN) {
1856 #ifdef KEY_MOUSE
1857 	if (key == KEY_MOUSE) {
1858 		CURSgetxy ();
1859 		keyproc = MOUSEfunction;
1860 		return FUNcmd;
1861 	}
1862 #endif
1863 	keyproc = lookup_curskey (key);
1864 	return FUNcmd;
1865   }
1866 #endif
1867   ch = key;
1868 
1869 #else	/* #ifdef CURSES */
1870 
1871 #ifdef dosmouse
1872   {
1873 	int ich = __readchar ();
1874 	if (ich == FUNcmd) {
1875 		DIRECTdosmousegetxy ();
1876 		keyproc = MOUSEfunction;
1877 		return FUNcmd;
1878 	} else {
1879 		ch = ich;
1880 	}
1881   }
1882 #else
1883   ch = read1byte ();
1884   if (ch == FUNcmd) {
1885 	/* pass back WINCH exception */
1886 	return FUNcmd;
1887   }
1888 #endif
1889 
1890 #endif	/* #else CURSES */
1891 
1892 
1893 #ifdef msdos
1894 
1895   if (ch > 0xFF) {
1896 	keyproc = pc_xkey_map [ch - 0x100].fp;
1897 	if (! keyproc) {
1898 		keyproc = I;
1899 	}
1900 	keyshift |= pc_xkey_map [ch - 0x100].fkeyshift;
1901 	return FUNcmd;
1902   }
1903 
1904   if (ch == '\000') {
1905 # ifdef dosmouse
1906 	ch = getch ();
1907 # else
1908 	ch = read1byte ();
1909 # endif
1910 	keyproc = pc_xkey_map [ch].fp;
1911 	if (! keyproc) {
1912 		keyproc = I;
1913 	}
1914 	keyshift |= pc_xkey_map [ch].fkeyshift;
1915 # ifdef debug_whatever
1916 	/* VAXC needs the identity cast (voidfunc) */
1917 	if ((voidfunc) keyproc == (voidfunc) I) {
1918 		return ch;
1919 	}
1920 # endif
1921 	return FUNcmd;
1922   } else if (ch == ' ' && (keyshift & ctrl_mask)) {
1923 	return 0;	/* ctrl-Space -> NUL */
1924   } else {
1925 	q_put (ch);
1926   }
1927 
1928 #else	/* #ifdef msdos */
1929 
1930   trace_keytrack ("_readchar<033", ch);
1931   if (ch == '\033') {
1932 	char second_esc_char = '\0';
1933 	int esc_wait = 2 * escape_delay;
1934 
1935 	q_put (ch);
1936 
1937 	if (! bytereadyafter (esc_wait, NIL_PTR)) {
1938 		return q_get ();
1939 	}
1940 
1941 	while ((res = findkey (ctrl_queue)) == -1 /* prefix of table entry */
1942 		&& q_notfull ()
1943 #ifdef simple_escape_delay_handling
1944 		&& bytereadyafter (escape_delay, NIL_PTR)
1945 #endif
1946 	      )
1947 	{
1948 		char prev_ch = ch;
1949 
1950 		if (prev_ch != '\033' && ! input_active && ! bytereadyafter (escape_delay, NIL_PTR)) {
1951 			status_uni ("...awaiting slow key code sequence...");
1952 		}
1953 
1954 		ch = get1byte ();
1955 #ifdef debug_kbesc
1956 		printf ("<^[%s> + [%dms] %02lX\n", ctrl_queue + 1, escape_delay, ch);
1957 #endif
1958 
1959 		/* accept ESC prefix as Alt modifier */
1960 		if (detect_esc_alt && ch == '\033' && prev_ch == '\033') {
1961 			if (bytereadyafter (escape_delay, NIL_PTR)) {
1962 				ch = get1byte ();
1963 				keyshift |= alt_mask;
1964 #ifdef debug_kbesc
1965 				printf ("-> <^[%s> + ^[/%02lX\n", ctrl_queue + 1, ch);
1966 #endif
1967 			}
1968 		}
1969 
1970 		/* accept XTerm*modifyCursorKeys: 3 as well as
1971 		   device attributes reports (primary/secondary DA) */
1972 		if (second_esc_char == '[' && prev_ch == '[' &&
1973 			(ch == '>' || ch == '?')
1974 		   ) {
1975 			if (ch == '?') {
1976 				keyshift |= report_mask;
1977 			}
1978 			ch = get1byte ();
1979 #ifdef debug_kbesc
1980 			printf ("-> <^[%s> + >?/%02lX\n", ctrl_queue + 1, ch);
1981 #endif
1982 		}
1983 
1984 check_ctrl_byte:
1985 		/* handle generic shift state of ANSI sequences: */
1986 		/* syntax of modifier indication varies with
1987 		   terminal type and mode; indications are as follows:
1988 					ANSI 1	ANSI 2	keyshift
1989 		   plain		-	9?	0x00
1990 		   Shift		2	10	0x01
1991 		   Alt			3	11	0x02
1992 		   Alt-Shift		4	12	0x03
1993 		   Control		5	13	0x04
1994 		   Control-Shift	6	14	0x05
1995 		   Alt-Control		7	15	0x06
1996 		   Alt-Control-Shift	8	16	0x07
1997 		   applkeypad_mask			0x08
1998 		 */
1999 		if (ch == ';' && second_esc_char == '[') {
2000 			ch = get1byte ();
2001 			if (ch >= '2' && ch <= '9') {
2002 				/* ESC [1;2A → ESC [1A + shift etc */
2003 				/* special: map '9' to applkeypad_mask */
2004 				keyshift |= (ch & ~'0') - 1;
2005 			} else if (ch == '1') {
2006 				ch = get1byte ();
2007 				if (ch >= '0' && ch <= '6') {
2008 					/* xterm with alwaysUseMods: */
2009 					/* ESC [1;11A → ESC [1A + alt etc */
2010 					keyshift |= applkeypad_mask | ((ch & ~'0') + 1);
2011 				} else {
2012 					q_put (';');
2013 					q_put ('1');
2014 					q_put (ch);
2015 				}
2016 			} else {
2017 				q_put (';');
2018 				q_put (ch);
2019 			}
2020 			ch = get1byte ();
2021 #ifdef debug_kbesc
2022 			printf ("-> <^[%s> + 1-8/%02lX\n", ctrl_queue + 1, ch);
2023 #endif
2024 		} else if (ch == ';' && second_esc_char == '1') {
2025 			ch = get1byte ();
2026 			if (ch >= '2' && ch <= '8') {
2027 				/* xterm/VT52 mode: ESC 1;2A → ESC 1A + shift etc */
2028 				keyshift |= (ch & ~'0') - 1;
2029 			} else {
2030 				q_put (';');
2031 				q_put (ch);
2032 			}
2033 			ch = get1byte ();
2034 #ifdef debug_kbesc
2035 			printf ("-> <^[%s> + ;/%02lX\n", ctrl_queue + 1, ch);
2036 #endif
2037 		} else if (ch >= '0' && ch <= '9'
2038 			   && (second_esc_char == 'O' ||
2039 			       (hp_shift_mode && ! second_esc_char))) {
2040 			if (ch >= '2' && ch <= '9') {
2041 				/* ESC O2A → ESC OA + shift etc */
2042 				/* HP: ESC 2p → ESC p + shift etc */
2043 				/* special: map '9' to applkeypad_mask */
2044 				keyshift |= (ch & ~'0') - 1;
2045 			} else if (ch == '1' || (ch == '0' && mlterm_version)) {
2046 				ch = get1byte ();
2047 				if (ch >= '0' && ch <= '6') {
2048 					/* ESC O11P → ESC OP + alt etc */
2049 					/* HP: ESC 11p → ESC p + alt etc */
2050 					keyshift |= applkeypad_mask | ((ch & ~'0') + 1);
2051 				} else if (ch == ';') {
2052 					/* mlterm: ESC O1;2A → ESC OA + shift etc */
2053 					/* mlterm: ESC O0;3w → ESC O0w + alt etc */
2054 					ch = get1byte ();
2055 					keyshift |= ((ch & ~'0') - 1);
2056 				} else {
2057 					q_put ('1');
2058 					q_put (ch);
2059 				}
2060 			} else {
2061 				q_put (ch);
2062 			}
2063 			ch = get1byte ();
2064 #ifdef debug_kbesc
2065 			printf ("-> <^[%s> + 0-9/%02lX\n", ctrl_queue + 1, ch);
2066 #endif
2067 		} else if (sco_shift_mode && second_esc_char == '['
2068 			   && ch >= '0' && ch <= '9') {
2069 			char newkeyshift;
2070 			char newch = '\0';
2071 			if (ch >= '2' && ch <= '9') {
2072 				/* SCO: ESC [2M → ESC [M + shift etc */
2073 				/* special: map '9' to applkeypad_mask */
2074 				newkeyshift = (ch & ~'0') - 1;
2075 				newch = get1byte ();
2076 #ifdef debug_kbesc
2077 				printf ("-> <^[%s> + 2-8/%02X\n", ctrl_queue + 1, newch);
2078 #endif
2079 				if (newch >= 'A' && newch <= 'Z') {
2080 					keyshift |= newkeyshift;
2081 				} else {
2082 					q_put (ch);
2083 				}
2084 			} else if (ch == '1') {
2085 				ch = get1byte ();
2086 #ifdef debug_kbesc
2087 				printf ("-> <^[%s> + 1/%02lX\n", ctrl_queue + 1, ch);
2088 #endif
2089 				if (ch >= '0' && ch <= '6') {
2090 					/* SCO: ESC [11M → ESC [M + alt etc */
2091 					newkeyshift = applkeypad_mask | ((ch & ~'0') + 1);
2092 					newch = get1byte ();
2093 					if (newch >= 'A' && newch <= 'Z') {
2094 						keyshift |= newkeyshift;
2095 					} else {
2096 						q_put ('1');
2097 						q_put (ch);
2098 					}
2099 				} else if (ch == ';') {
2100 					/* xterm SCO: ESC [1;5R → ESC [R + alt etc */
2101 					ch = get1byte ();
2102 					keyshift |= (ch & ~'0') - 1;
2103 					newch = get1byte ();
2104 				} else {
2105 					q_put ('1');
2106 					q_put (ch);
2107 					newch = get1byte ();
2108 				}
2109 			} else {
2110 #ifdef debug_kbesc
2111 				printf ("-> <^[%s>\n", ctrl_queue + 1);
2112 #endif
2113 				q_put (ch);
2114 				newch = get1byte ();
2115 			}
2116 			ch = newch;
2117 			if (ch == ';') {
2118 				/* OK, so here is my second goto;
2119 				   this is really a very peculiar case,
2120 				   based on misconfiguration
2121 				   (mined assumes sco, terminal sends
2122 				   modified xterm sequences),
2123 				   which does not deserve any
2124 				   goto avoidance effort
2125 				*/
2126 #ifdef debug_kbesc
2127 				printf ("goto check_ctrl_byte\n");
2128 #endif
2129 				goto check_ctrl_byte;
2130 			}
2131 		} else if (prev_ch >= '0' && prev_ch <= '9') {
2132 			if (ch == '^') {
2133 				/* ESC [5^ → ESC [5~ + control (rxvt) */
2134 				keyshift |= ctrl_mask;
2135 				ch = '~';
2136 			} else if (ch == '$') {
2137 				/* ESC [5$ → ESC [5~ + shift (rxvt) */
2138 				keyshift |= shift_mask;
2139 				ch = '~';
2140 			} else if (ch == '@') {
2141 				/* ESC [5@ → ESC [5~ + control+shift (rxvt) */
2142 				keyshift |= ctrlshift_mask;
2143 				ch = '~';
2144 			}
2145 		} else if (ch >= 'a' && ch <= 'd') {
2146 			if (prev_ch == 'O') {
2147 				/* ESC Oa → ESC OA + control (rxvt) */
2148 				keyshift |= ctrl_mask;
2149 				ch -= 'a' - 'A';
2150 			} else if (prev_ch == '[') {
2151 				/* ESC [a → ESC [A + shift (rxvt) */
2152 				keyshift |= shift_mask;
2153 				ch -= 'a' - 'A';
2154 			}
2155 		}
2156 
2157 		q_put (ch);
2158 		if (second_esc_char == '\0') {
2159 			second_esc_char = ch;
2160 			if (second_esc_char == 'O') {
2161 				/* appl. cursor keys, appl. keypad */
2162 				keyshift |= applkeypad_mask;
2163 			}
2164 		}
2165 	}
2166 #ifdef debug_kbesc
2167 	printf ("=> [%d] <^[%s> [keyshift %X]\n", res, ctrl_queue + 1, keyshift);
2168 #endif
2169 #ifdef debug_kbansi
2170 	printf ("[%d] [keyshift %X]\n", res, keyshift);
2171 #endif
2172 
2173 	if (quit) {
2174 		keyproc = I;
2175 		return FUNcmd;
2176 	} else if (res < 0) {	/* key pattern not found in fkeymap table */
2177 		if (second_esc_char == '[') {
2178 			/* generic scanning for unknown ANSI sequence */
2179 #ifdef debug_kbansi
2180 			character q1, q2;
2181 			q1 = q_get (); /* swallow ESC */
2182 			q2 = q_get (); /* swallow [ */
2183 			printf ("swallowing %X %X\n", q1, q2);
2184 #else
2185 			(void) q_get (); /* swallow ESC */
2186 			(void) q_get (); /* swallow [ */
2187 #endif
2188 			/* (Was putback_rest (ctrl_queue + 2);) */
2189 			/* Use raw_queue to ignore previous modifier
2190 			   transformations like ESC [1;11A → ESC [1A + alt */
2191 			if ((keyshift & alt_mask) && raw_queue [1] == '[') {
2192 				/* consider double-ESC alt (rxvt) */
2193 				putback_rest (raw_queue + 2);
2194 			} else {
2195 				putback_rest (raw_queue + 1);
2196 			}
2197 
2198 			ansi_params = 0;
2199 			ansi_ini = '\0';
2200 			do {
2201 				int i = -1;
2202 				ansi_fini = get_digits (& i);
2203 				if (ansi_params == 0 && i == -1 &&
2204 				   (ansi_fini == '>' || ansi_fini == '?' || ansi_fini == '<')
2205 				   ) {
2206 					ansi_ini = ansi_fini;
2207 					ansi_fini = ';';
2208 				} else if (ansi_params < max_ansi_params) {
2209 					ansi_param [ansi_params] = i;
2210 					ansi_params ++;
2211 				}
2212 			} while (ansi_fini == ';');
2213 			q_clear ();
2214 #ifdef debug_kbansi
2215 			printf ("ansi %c (%d)", ansi_fini, ansi_params);
2216 			{int i;
2217 			 for (i = 0; i < ansi_params; i ++) {
2218 				printf (" %d", ansi_param [i]);
2219 			 }
2220 			}
2221 			printf ("\n");
2222 #endif
2223 
2224 			if ((ansi_fini == '~'
2225 			     && ansi_param [0] == 27
2226 			     && ansi_params >= 3
2227 			    )
2228 			 || (ansi_fini == 'u'
2229 			     && (ansi_params == 2
2230 			      || (ansi_params == 1 && keyshift > 0)
2231 			        )
2232 			    )
2233 			   ) {
2234 				/* map xterm 235 mode formatOtherKeys: 1
2235 					^[[77;2u
2236 				   to xterm mode formatOtherKeys: 0
2237 					^[[27;2;77~
2238 				 */
2239 				if (ansi_fini == 'u') {
2240 					ansi_param [2] = ansi_param [0];
2241 				}
2242 
2243 				if (ansi_params > 1) {
2244 					/* handle generic escape sequence
2245 					   for modified key
2246 					   (xterm 214 resource modifyOtherKeys)
2247 					 */
2248 					if (ansi_param [1] > 8) {
2249 						ansi_param [1] -= 8;
2250 					}
2251 					keyshift |= ansi_param [1] - 1;
2252 				}
2253 
2254 				/* enforce UTF-8 interpretation of input */
2255 				queue_mode_mapped = True;
2256 
2257 				if (ansi_param [2] == ' ' && (keyshift & ctrlshift_mask) == ctrl_mask) {
2258 					/* map ctrl-space to MARK,
2259 					   alt-ctrl-space to Hop MARK */
2260 					q_put ('\0');
2261 				} else if (ansi_param [2] == 0) {
2262 					q_put ('\0');
2263 				} else {
2264 					char cbuf [7];
2265 					char * cp = cbuf;
2266 
2267 					/* Shift-a/A -> A */
2268 					if ((keyshift & altctrlshift_mask) == shift_mask
2269 					   && isLetter (ansi_param [2])
2270 					   ) {
2271 						keyshift = 0;
2272 						ansi_param [2] = case_convert (ansi_param [2], 1);
2273 					}
2274 
2275 					/* Control-/ etc as accent prefix */
2276 					if (keyshift & ctrl_mask) {
2277 						struct prefixspec * ps;
2278 						ps = lookup_prefix (COMPOSE, ansi_param [2]);
2279 						if (ps && * ps->accentname) {
2280 							keyshift = ansi_param [2];
2281 							keyproc = COMPOSE;
2282 							return FUNcmd;
2283 						} else if (ps) {
2284 							unsigned long unichar;
2285 							int len;
2286 							utf8_info (ps->pat1, & len, & unichar);
2287 							ansi_param [2] = unichar;
2288 						} else if ('?' <= ansi_param [2] && ansi_param [2] < '') {
2289 							keyshift &= ~ ctrl_mask;
2290 							return ansi_param [2] & 0x1F;
2291 						}
2292 					}
2293 
2294 					(void) utfencode (ansi_param [2], cbuf);
2295 					while (* cp) {
2296 						q_put (* cp ++);
2297 					}
2298 				}
2299 
2300 				/* Control/Alt/Control-Alt-0 -> ...key_0 */
2301 				if (ansi_param [2] >= '0' && ansi_param [2] <= '9') {
2302 					switch (ansi_param [2]) {
2303 					case '0': keyproc = key_0; break;
2304 					case '1': keyproc = key_1; break;
2305 					case '2': keyproc = key_2; break;
2306 					case '3': keyproc = key_3; break;
2307 					case '4': keyproc = key_4; break;
2308 					case '5': keyproc = key_5; break;
2309 					case '6': keyproc = key_6; break;
2310 					case '7': keyproc = key_7; break;
2311 					case '8': keyproc = key_8; break;
2312 					case '9': keyproc = key_9; break;
2313 					}
2314 					q_clear ();
2315 					return FUNcmd;
2316 				}
2317 
2318 				if (keyshift & alt_mask) {
2319 					/* 2000.13 workaround for prompt */
2320 					if ((keyshift & altctrl_mask) == alt_mask) {
2321 					    if (ansi_param [2] == 'k') {
2322 						q_clear ();
2323 						keyproc = toggleKEYMAP;
2324 						return FUNcmd;
2325 					    }
2326 					    if (ansi_param [2] == 'K'
2327 					     || ansi_param [2] == 'I') {
2328 						q_clear ();
2329 						keyproc = setupKEYMAP;
2330 						return FUNcmd;
2331 					    }
2332 					}
2333 
2334 					return '\033';
2335 				} else if (keyshift) {
2336 					return q_get ();
2337 				} else {
2338 					/* fall through to keyboard mapping */
2339 				}
2340 			} else {	/* not CSI 27 sequence */
2341 				if (ansi_fini == '&') {	/* DEC locator report */
2342 					(void) read1byte ();	/* swallow 'w' */
2343 					if (ansi_params < 4) {
2344 						ansi_param [3] = 1;
2345 						if (ansi_params < 3) {
2346 							ansi_param [2] = 1;
2347 						}
2348 					}
2349 					DIRECTvtlocatorgetxy ();
2350 					keyproc = MOUSEfunction;
2351 				} else if (ansi_ini == '<') {
2352 					DIRECTsgrgetxy ();
2353 					keyproc = MOUSEfunction;
2354 				} else if (! ansi_ini && ansi_fini == 'M') {
2355 					DIRECTurxvtgetxy ();
2356 					keyproc = MOUSEfunction;
2357 				} else {
2358 					keyproc = ANSIseq;
2359 				}
2360 				return FUNcmd;
2361 			}
2362 		} else if (keyshift & alt_mask) {
2363 			/* restore the previously filtered ESCAPE */
2364 			return '\033';
2365 		} else {
2366 			/* just deliver the typed characters */
2367 			return q_get ();
2368 		}
2369 	} else {	/* key pattern found in fkeymap table */
2370 		q_clear ();
2371 
2372 		keyshift |= fkeyshift;
2373 
2374 		if (keyproc == ESCAPE) {
2375 			/* mintty application escape key mode */
2376 			return '\033';
2377 		} else if (keyproc == DIRECTxterm) {
2378 #ifdef debug_mouse
2379 			printf ("scanned xterm mouse escape\n");
2380 #endif
2381 			DIRECTxtermgetxy ('M');
2382 			keyproc = MOUSEfunction;
2383 		} else if (keyproc == TRACKxterm) {
2384 #ifdef debug_mouse
2385 			printf ("scanned xterm mouse tracking escape\n");
2386 #endif
2387 			DIRECTxtermgetxy ('t');
2388 			keyproc = MOUSEfunction;
2389 		} else if (keyproc == TRACKxtermT) {
2390 #ifdef debug_mouse
2391 			printf ("scanned xterm mouse tracking escape\n");
2392 #endif
2393 			DIRECTxtermgetxy ('T');
2394 			keyproc = MOUSEfunction;
2395 		} else if (keyproc == DIRECTcrttool) {
2396 			DIRECTcrttoolgetxy ();
2397 			keyproc = MOUSEfunction;
2398 		}
2399 
2400 		return FUNcmd;
2401 	}
2402   } else {
2403 	q_put (ch);
2404   }
2405 
2406 #endif	/* #else msdos */
2407 
2408   if (allow_keymap && dont_suppress_keymap && keyboard_mapping_active ()) {
2409 	disable_modify_keys (True);
2410 	while  ((res = map_key (ctrl_queue, 1, & found, & mapped)) == -1
2411 		 /* prefix of some table entry */
2412 		&& q_notfull ()
2413 		&& bytereadyafter (keymap_delay, NIL_PTR)
2414 	       )
2415 	{
2416 #ifdef fix_modified_input
2417 		/* avoid xterm modifyOtherKeys mode to interfere with
2418 		   input method handling: will have to use separate queue
2419 		 */
2420 		q_put (_readchar_nokeymap ());
2421 		plainly like this, we get an endless loop...
2422 		now using disable_modify_keys workaround
2423 #else
2424 		q_put (read1byte ());
2425 #endif
2426 		/* exact match found? note for later consideration */
2427 		if (found != NIL_PTR) {
2428 			prev_found = found;
2429 		}
2430 	}
2431 	disable_modify_keys (False);
2432 	/* possible results:
2433 		res >= 0: match found, no further prefix match
2434 		res == -1, prev_found != NIL_PTR: prefix with previous match
2435 		res == -1: prefix only, no further key typed
2436 		res == -2: no match with previous match
2437 	*/
2438 
2439 #ifdef debug_kbmap
2440 	printf ("mapping %s, res %d, found %s -> ", ctrl_queue, res, found);
2441 #endif
2442 	if (res < 0 && prev_found != NIL_PTR) {
2443 		res = 1;
2444 		if (found == NIL_PTR) {
2445 #ifdef debug_kbmap
2446 			printf ("rest %s, ", ctrl_queue + strlen (prev_found));
2447 #endif
2448 			putback_rest (ctrl_queue + strlen (prev_found));
2449 		}
2450 	} else if (res == -1) {
2451 		res = map_key (ctrl_queue, 2, & found, & mapped);
2452 #ifdef debug_kbmap
2453 		printf ("find again %s, found %s, ", ctrl_queue, found);
2454 #endif
2455 	}
2456 
2457 #ifdef debug_kbmap
2458 	printf ("res %d\n", res);
2459 #endif
2460 
2461 	if (res >= 0) { /* key pattern detected in key mapping table */
2462 
2463 handle_mapped:
2464 		q_clear ();
2465 
2466 		/* check if mapping defines multiple choices */
2467 		while (* mapped == ' ') {
2468 			mapped ++;
2469 		}
2470 		choice = strchr (mapped, ' ');
2471 		while (choice != NIL_PTR && * choice == ' ') {
2472 			choice ++;
2473 		}
2474 		if (choice != NIL_PTR && * choice != '\0') {
2475 			choice_index = choose_char (mapped);
2476 #ifdef debug_kbmap
2477 			printf (" choose_char (%s) -> %d\n", mapped, choice_index);
2478 #endif
2479 			if (choice_index < 0) {
2480 				mapped = NIL_PTR;
2481 				/* mapping cancelled */
2482 			} else {
2483 				while (choice_index > 0
2484 					&& mapped != NIL_PTR
2485 					&& * mapped != '\0')
2486 				{
2487 					mapped = strchr (mapped, ' ');
2488 					if (mapped != NIL_PTR) {
2489 						while (* mapped == ' ') {
2490 							mapped ++;
2491 						}
2492 					}
2493 					choice_index --;
2494 				}
2495 			}
2496 		}
2497 
2498 		if (mapped != NIL_PTR) {
2499 			queue_mode_mapped = True;
2500 			while (* mapped != '\0' && * mapped != ' ') {
2501 				q_put (* mapped);
2502 				mapped ++;
2503 			}
2504 		}
2505 #ifdef debug_kbmap
2506 		printf (" queued %s\n", ctrl_queue);
2507 #endif
2508 	}
2509 
2510 	if (q_len () > 0) {
2511 		return q_get () /* deliver the first mapped byte */;
2512 	} else {
2513 		ring_bell ();
2514 		flush ();	/* clear key mapping menu */
2515 #define return_after_esc
2516 #ifdef return_after_esc
2517 		return CHAR_UNKNOWN;	/* actually "CHAR_NONE" */
2518 #else
2519 		if (is_menu_open () /* doesn't seem to work */) {
2520 			return CHAR_UNKNOWN;	/* actually "CHAR_NONE" */
2521 		} else {
2522 			/* read another character */
2523 			/* prompt should have been redrawn;
2524 			   menu (file chooser) would stay blank...
2525 			 */
2526 			return _readchar ();
2527 		}
2528 #endif
2529 	}
2530   } else {	/* not keyboard mapped */
2531 	return q_get ();
2532   }
2533 
2534 }
2535 
2536 
2537 #define dont_debug_choose_char
2538 
2539 static
2540 int
choose_char(choices)2541 choose_char (choices)
2542   char * choices;
2543 {
2544   int choice_count = 0;
2545   char * choicepoi = choices;
2546   int choice_col = x;
2547   int choice_line = y + 1;
2548 
2549   char * thischoiceline;
2550   char * choicelines;
2551   menuitemtype * choicemenu;
2552 
2553   int li, ci, lastcol, lastrow;
2554   char * choicelinepoi;
2555 
2556   int selected;
2557 
2558 #ifdef cut_picklist_to_screen
2559   FLAG reduced_menu = False;
2560 #endif
2561 
2562 	/* count choices */
2563 	do {
2564 		choice_count ++;
2565 		choicepoi = strchr (choicepoi, ' ');
2566 		while (choicepoi != NIL_PTR && * choicepoi == ' ') {
2567 			choicepoi ++;
2568 		}
2569 	} while (choicepoi != NIL_PTR && * choicepoi != '\0');
2570 #ifdef debug_choose_char
2571 	printf ("choices <%s>\n", choices);
2572 	printf ("choice_count %d\n", choice_count);
2573 #endif
2574 
2575 	lastrow = (choice_count - 1) / 10;
2576 	choicelines = alloc (strlen (choices) + 1 + choice_count * 2);
2577 	choicemenu = alloc ((lastrow + 1) * sizeof (menuitemtype));
2578 	if (choicelines == NIL_PTR || choicemenu == (menuitemtype *) NIL_PTR) {
2579 		if (choicelines != NIL_PTR) {
2580 			free_space (choicelines);
2581 		}
2582 		ring_bell ();
2583 		flush ();
2584 		return -1;
2585 	}
2586 
2587 	/* adjust menu position if too far down */
2588 	if (choice_line + lastrow + 3 > YMAX) {
2589 		choice_line = y - lastrow - 3;
2590 		if (choice_line < 0) {
2591 			choice_line = 0;
2592 		}
2593 	}
2594 
2595 	/* adjust menu position if on status line */
2596 	if (input_active) {
2597 		choice_line = YMAX - lastrow - 3;
2598 		if (choice_line < 0) {
2599 			choice_line = 0;
2600 		}
2601 		choice_col = lpos;
2602 	}
2603 
2604 	/* construct menu items */
2605 	choicepoi = choices;
2606 	while (* choicepoi == ' ') {
2607 		choicepoi ++;
2608 	}
2609 	thischoiceline = choicelines;
2610 	for (li = 0; li <= lastrow; li ++) {
2611 		/* construct menu line */
2612 		choicelinepoi = thischoiceline;
2613 		if (li == lastrow) {
2614 			lastcol = (choice_count - 1) % 10;
2615 			if (lastcol < 0) {
2616 				/* should not occur as choice_count > 0 */
2617 				lastcol = 0;
2618 			}
2619 		} else {
2620 			lastcol = 9;
2621 		}
2622 		for (ci = 0; ci <= lastcol; ci ++) {
2623 			* choicelinepoi ++ = (ci + 1) % 10 + '0';
2624 			* choicelinepoi ++ = ':';
2625 			while (* choicepoi != ' ' && * choicepoi != '\0') {
2626 				* choicelinepoi ++ = * choicepoi ++;
2627 			}
2628 			while (* choicepoi == ' ') {
2629 				choicepoi ++;
2630 			}
2631 			if (ci < lastcol) {
2632 				* choicelinepoi ++ = ' ';
2633 			}
2634 		}
2635 		* choicelinepoi ++ = '\0';
2636 		/* add menu line to menu */
2637 #ifdef debug_choose_char
2638 		printf ("choiceline <%s>\n", thischoiceline);
2639 #endif
2640 		/* fill menu item with collected data */
2641 		fill_menuitem (& choicemenu [li], thischoiceline, NIL_PTR);
2642 
2643 		thischoiceline = choicelinepoi;
2644 	}
2645 #ifdef debug_choose_char
2646 	printf ("choicelines alloc %d length %d\n",
2647 		strlen (choices) + 1 + choice_count * 2 + lastrow + 1,
2648 		thischoiceline - choicelines);
2649 #endif
2650 
2651 #ifdef cut_picklist_to_screen
2652 	if (lastrow >= YMAX - 2) {
2653 		lastrow = YMAX - 3;
2654 		reduced_menu = True;
2655 		if (! input_active) {
2656 			status_msg ("Warning: full menu too large to display");
2657 		}
2658 	}
2659 #endif
2660 	selected = popup_menu (choicemenu, lastrow + 1,
2661 				choice_col, choice_line,
2662 				"Choose character", False, False, "1234567890");
2663 	if (input_active) {
2664 		/* redraw_prompt () now checked and called in input () */
2665 #ifdef cut_picklist_to_screen
2666 	} else if (reduced_menu) {
2667 		clear_status ();
2668 #endif
2669 	}
2670 
2671 #ifdef debug_choose_char
2672 	printf ("selected %d\n", selected);
2673 #endif
2674 
2675 	free_space (choicemenu);
2676 	free_space (choicelines);
2677 
2678 	if (selected < choice_count) {
2679 		return selected;
2680 	} else {
2681 		return -1;
2682 	}
2683 }
2684 
2685 
2686 /*======================================================================*\
2687 |*				End					*|
2688 \*======================================================================*/
2689