/*======================================================================*\ |* Editor mined *| |* keyboard input *| \*======================================================================*/ #include "mined.h" #include "io.h" #include "termprop.h" #ifndef __TURBOC__ #include #endif #ifdef CURSES #include #include #endif voidfunc keyproc = I; /* function addressed by entered function key */ unsigned char keyshift = 0; /* shift state of entered function key */ static unsigned char fkeyshift; #define max_ansi_params 10 int ansi_params; int ansi_param [max_ansi_params]; char ansi_fini; static int keymap_delay = 0; /* wait to detect mapped key sequence */ static int default_keymap_delay = 900; /* overridden by $MAPDELAY */ static int escape_delay = 0; /* wait to detect escape sequence */ static int default_escape_delay = 450; /* overridden by $ESCDELAY */ static int dont_suppress_keymap = 1; static int report_winchg = 0; /* The flag queue_mode_mapped indicates when the byte input queue has been stuffed with keyboard mapped characters, always being encoded in UTF-8, while otherwise the queue contents are in terminal native encoding (which may also be UTF-8, or CJK, or Latin-1). */ static FLAG queue_mode_mapped = False; /* queue contains mapped character(s) */ /* In hp_shift_mode key shift indications like ESC 2p or ESC 5h are considered to determine the keyshift state. */ static FLAG hp_shift_mode = False; /* In sco_shift_mode key shift indications like ESC [2A or ESC [2M are considered to determine the keyshift state. */ static FLAG sco_shift_mode = False; /*======================================================================*\ |* Local function declaration *| \*======================================================================*/ static unsigned long _readchar _((void)); /*======================================================================*\ |* Handling function key and keyboard mapping tables *| \*======================================================================*/ #ifndef msdos static void dummyfunc () { } extern struct fkeyentry fkeymap []; extern struct fkeyentry fkeymap_xterm []; extern struct fkeyentry fkeymap_rxvt []; extern struct fkeyentry fkeymap_vt100 []; extern struct fkeyentry fkeymap_vt52 []; extern struct fkeyentry fkeymap_hp []; extern struct fkeyentry fkeymap_siemens []; extern struct fkeyentry fkeymap_scoansi []; extern struct fkeyentry fkeymap_interix []; static struct fkeyentry * fkeymap_spec = fkeymap_xterm; extern struct fkeyentry fkeymap_terminfo []; void set_fkeymap (term) char * term; { if (term == NIL_PTR) { return; } else if (* term == 'x') { fkeymap_spec = fkeymap_xterm; } else if (* term == 'r') { fkeymap_spec = fkeymap_rxvt; } else if (* term == 'h') { fkeymap_spec = fkeymap_hp; hp_shift_mode = True; } else if (* term == 'v') { fkeymap_spec = fkeymap_vt100; } else if (* term == '5') { fkeymap_spec = fkeymap_vt52; } else if (* term == 'i') { fkeymap_spec = fkeymap_interix; } else if (* term == 's') { fkeymap_spec = fkeymap_siemens; use_mouse = False; } else if (* term == 'o') { fkeymap_spec = fkeymap_scoansi; sco_shift_mode = True; use_mouse = False; } } #else void set_fkeymap (term) char * term; { } #endif char * keyboard_mapping = "--"; static char * last_keyboard_mapping = "--"; static char * next_keyboard_mapping = ""; static keymaptabletype keyboard_map = (keymaptabletype) NIL_PTR; static keymaptabletype last_keyboard_map = (keymaptabletype) NIL_PTR; /** Notify user of changed input method */ static void notify_input_method () { menuitemtype * km = lookup_Keymap_menuitem (keyboard_mapping); char * source = NIL_PTR; switch (km->extratag ? km->extratag [0] : ' ') { case 'U': source = "UnicodeData"; break; case 'H': source = "Unihan"; break; case 'C': source = "cxterm"; break; case 'M': source = "m17n"; break; case 'Y': source = "yudit"; break; case 'V': source = "vim"; break; case 'X': source = "X"; break; } if (source) { build_string (text_buffer, "Input method: %s (source: %s)", km->itemname, source); } else { build_string (text_buffer, "Input method: %s", km->itemname); } status_msg (text_buffer); } /** Set keymap. */ static void set_keymap (new_keymap, current, next) keymaptabletype new_keymap; char * current; char * next; { last_keyboard_map = keyboard_map; last_keyboard_mapping = keyboard_mapping; keyboard_map = new_keymap; keyboard_mapping = current; next_keyboard_mapping = next; if (! loading && ! in_status_line) { notify_input_method (); } } /** Exchange current and previous keyboard mapping; set previous active. With HOP, reset keyboard mapping to none. */ void toggleKEYMAP () { if (allow_keymap) { if (hop_flag > 0) { set_keymap ((keymaptabletype) NIL_PTR, "--", keymappingtable [0].shortcut); } else { set_keymap (last_keyboard_map, last_keyboard_mapping, last_keyboard_mapping); } flags_changed = True; } else { error ("Keyboard mapping not active"); } } /** Set keyboard mapping. */ static FLAG selectKEYMAP (script) char * script; { int i; if (script == NIL_PTR || * script == '\0') { set_keymap ((keymaptabletype) NIL_PTR, "--", keymappingtable [0].shortcut); flags_changed = True; return True; } else { /* map alternative shortcuts */ if (strisprefix ("el", script)) { script = "gr"; } else if (strisprefix ("ru", script)) { script = "cy"; } /* map shortcut to keymap */ for (i = 0; i < keymappingtable_len; i ++) { if (strisprefix (keymappingtable [i].shortcut, script)) { set_keymap (keymappingtable [i].table, keymappingtable [i].shortcut, i + 1 == keymappingtable_len ? "" : keymappingtable [i + 1].shortcut); flags_changed = True; return True; } } return False; } } /** Set keyboard mapping. */ void setKEYMAP (script) char * script; { if (script != NIL_PTR && * script == '-') { /* set keymap as secondary map */ script ++; selectKEYMAP (script); selectKEYMAP (NIL_PTR); } else if (script != NIL_PTR) { char * secondary = strchr (script, '-'); if (secondary != NIL_PTR) { secondary ++; selectKEYMAP (secondary); } selectKEYMAP (script); } } #ifdef not_used /** Cycle through keyboard mappings. */ void cycleKEYMAP () { selectKEYMAP (next_keyboard_mapping); } #endif /** Enable keyboard mapping interactively. With HOP, cycle through keyboard mappings. */ void setupKEYMAP () { if (allow_keymap) { if (hop_flag > 0) { hop_flag = 0; selectKEYMAP (next_keyboard_mapping); } else { handleKeymapmenu (); } } else { error ("Keyboard mapping not active"); } } /** get_string_nokeymap prompts a string like get_string but doesn't apply international keyboard mapping */ int get_string_nokeymap (prompt, inbuf, statfl, term_input) char * prompt; char * inbuf; FLAG statfl; char * term_input; { int ret; dont_suppress_keymap = 0; ret = get_string (prompt, inbuf, statfl, term_input); dont_suppress_keymap = 1; return ret; } /*======================================================================*\ |* Digits input *| \*======================================================================*/ /** get_digits () reads in a number. In contrast to get_number, it does no echoing, no messaging, reads only decimal, and accepts zero length input. The last character typed in is returned. The resulting number is put into the integer the arguments points to. It is for use within I/O routines (e.g. reading mouse escape sequences or cursor position report) and thus calls _readchar (). */ int get_digits (result) int * result; { register int index; register int count; index = read1byte (); if (index == quit_char) { quit = True; } * result = -1; /* Convert input to a decimal number */ count = 0; while (index >= '0' && index <= '9' && quit == False) { count *= 10; count += index - '0'; * result = count; index = read1byte (); if (index == quit_char) { quit = True; } } if (quit) { return quit_char; } return index; } /*======================================================================*\ |* Terminal input *| \*======================================================================*/ #define dont_debug_mapped_keyboard #define dont_debug_focus #define max_stamps 10 static long last_sec = 0; static long last_msec = 0; static int n_stamps = 0; static int i_stamp = 0; static long stamps [max_stamps]; static long total_deltas = 0; long average_delta_readchar = 0; long last_delta_readchar = 0; static FLAG skip_1click = False; static FLAG skip_1release = False; static void timestamp_readchar () { #ifndef __TURBOC__ struct timeval now; long sec; long msec; gettimeofday (& now, 0); sec = now.tv_sec; msec = now.tv_usec / 1000; if (last_sec == 0) { last_delta_readchar = 1000; } else { last_delta_readchar = (sec - last_sec) * 1000 + msec - last_msec; } last_sec = sec; last_msec = msec; if (n_stamps < max_stamps) { n_stamps ++; } else { /* remove oldest stamp from statistics */ total_deltas -= stamps [i_stamp]; } stamps [i_stamp] = last_delta_readchar; /* add stamp to statistics */ total_deltas += last_delta_readchar; i_stamp ++; if (i_stamp == max_stamps) { i_stamp = 0; } average_delta_readchar = total_deltas / n_stamps; #endif } /* * Readchar () reads one character from the terminal. * There are problems due to interruption of the read operation by signals * (QUIT, WINCH). The waitingforinput flag is only a partial solution. * Unix doesn't provide sufficient facilities to handle these situations * neatly and properly. Moreover, different Unix versions yield different * surprising effects. However, the use of select () could still be * an improvement. */ static unsigned long readchar () { unsigned long c; #ifdef msdos #define winchhere #endif #ifdef winchhere FLAG waiting; if (winchg && waitingforinput == False) { /* In the Unix version, this is now done in __readchar () */ RDwin (); } /* must save waitingforinput flag since in the MSDOS version, readchar can be called recursively */ waiting = waitingforinput; #endif waitingforinput = True; c = _readchar (); while (command (c) == MOUSEescape && mouse_button == releasebutton && report_release == False) { #ifdef debug_focus printf ("ignoring MOUSE release event\n"); #endif c = _readchar (); } report_release = False; #ifdef winchhere waitingforinput = waiting; #else waitingforinput = False; #endif /* the modification if (quit) { c = quit_char; } (now in __readchar) must not be placed after resetting the flag waitingforinput = False; Otherwise a QUIT signal coming in just between these two would discard the last valid character just taken up. */ timestamp_readchar (); return c; } /* readchar_nokeymap reads like readchar but doesn't apply international keyboard mapping */ static unsigned long readchar_nokeymap () { unsigned long c; int prev_dont_suppress_keymap = dont_suppress_keymap; dont_suppress_keymap = 0; c = readchar (); dont_suppress_keymap = prev_dont_suppress_keymap; return c; } /* readcharacter_allbuttons reads like readcharacter but always reports mouse button release and also reports window size change as function RDwin */ unsigned long readcharacter_allbuttons () { unsigned long c; int prev_report_winchg = report_winchg; report_winchg = 1; report_release = True; c = readcharacter (); report_winchg = prev_report_winchg; return c; } /* readcharacter_mapping () reads one character either with or without keyboard mapping */ static unsigned long readcharacter_mapping (map_keyboard, return_unicode) FLAG map_keyboard; FLAG return_unicode; { int utfcount = 1; unsigned long unichar; int byte2; if (map_keyboard) { unichar = readchar (); } else { unichar = readchar_nokeymap (); /* double check needed here because command ('\n') == SNL */ if (unichar == FUNcmd && command (unichar) == SNL) { return '\r'; } } if (unichar == FUNcmd) { /** housekeeping of some events to cover the cases: focus-out mouse-click focus-in mouse-release (xterm 224) focus-out mouse-click mouse-release focus-in focus-out focus-in mouse-click mouse-release and ignore the first mouse click/release in any case */ FLAG skipmouse = False; if (command (unichar) == FOCUSout) { #ifdef debug_focus printf ("FOCUS out\n"); #endif FOCUSout (); skip_1click = True; skip_1release = True; skipmouse = True; } else if (command (unichar) == FOCUSin) { #ifdef debug_focus printf ("FOCUS in\n"); #endif FOCUSin (); skipmouse = True; } else if (command (unichar) == MOUSEescape) { if (mouse_button == releasebutton && skip_1release) { #ifdef debug_focus printf ("skipping 1 MOUSE release event\n"); #endif skipmouse = True; skip_1release = False; } else if (mouse_button != releasebutton && skip_1click) { #ifdef debug_focus printf ("skipping 1 MOUSE event\n"); #endif skipmouse = True; skip_1click = False; skip_1release = False; } else if (! window_focus) { /* should not be needed anymore */ #ifdef debug_focus printf ("skipping MOUSE event while focus out\n"); #endif skipmouse = True; } } if (skipmouse) { return readcharacter_mapping (map_keyboard, return_unicode); } else { /* WINCH exception isn't passing by here... */ #ifdef debug_focus if (command (unichar) == MOUSEescape) { if (mouse_button == releasebutton) { printf ("passing MOUSE release event\n"); } else { printf ("passing MOUSE event\n"); } } #endif return FUNcmd; } } if (utf8_input || queue_mode_mapped) { if ((unichar & 0x80) == 0x00) { utfcount = 1; } else if ((unichar & 0xE0) == 0xC0) { utfcount = 2; unichar = unichar & 0x1F; } else if ((unichar & 0xF0) == 0xE0) { utfcount = 3; unichar = unichar & 0x0F; } else if ((unichar & 0xF8) == 0xF0) { utfcount = 4; unichar = unichar & 0x07; } else if ((unichar & 0xFC) == 0xF8) { utfcount = 5; unichar = unichar & 0x03; } else if ((unichar & 0xFE) == 0xFC) { utfcount = 6; unichar = unichar & 0x01; } else /* illegal UTF-8 code */ { return unichar; } while (utfcount > 1) { unichar = (unichar << 6) | (readchar_nokeymap () & 0x3F); utfcount --; } if (! return_unicode && (cjk_text || mapped_text)) { return encodedchar (unichar); } else { return unichar; } } else if (cjk_term && multichar (unichar)) { if (text_encoding_tag == 'C' && unichar == 0x8E) { unichar = (unichar << 24) | (readchar_nokeymap () << 16) | (readchar_nokeymap () << 8) | readchar_nokeymap (); } else if (text_encoding_tag == 'J' && unichar == 0x8F) { unichar = (unichar << 16) | (readchar_nokeymap () << 8) | readchar_nokeymap (); } else { byte2 = readchar_nokeymap (); if (text_encoding_tag == 'G' && '0' <= byte2 && byte2 <= '9') { unichar = (unichar << 24) | (byte2 << 16) | (readchar_nokeymap () << 8) | readchar_nokeymap (); } else { unichar = (unichar << 8) | byte2; } } if (return_unicode || utf8_text) { unichar = lookup_encodedchar (unichar); } return unichar; } else { if (mapped_term) { if (! return_unicode && (cjk_text || mapped_text) && ! remap_chars ()) { #ifdef debug_mapped_keyboard printf ("rc_m mapped (ret_u %d) -> %04X\n", return_unicode, unichar); #endif return unichar; } else { #ifdef debug_mapped_keyboard printf ("rc_m mapped (ret_u %d) -> %04X -> %04X ...\n", return_unicode, unichar, lookup_mappedtermchar (unichar)); #endif unichar = lookup_mappedtermchar (unichar); if (no_unichar (unichar)) { #ifdef debug_mapped_keyboard printf ("rc_m mapped -> CHAR_INVALID\n"); #endif return CHAR_INVALID; } } } if (! return_unicode && (cjk_text || mapped_text)) { #ifdef debug_mapped_keyboard printf ("rc_m -> %04X -> %04X\n", unichar, encodedchar (unichar)); #endif return encodedchar (unichar); } else { #ifdef debug_mapped_keyboard printf ("rc_m -> %04X\n", unichar); #endif return unichar; } } } /* readcharacter () reads one character keyboard mapping is suppressed */ unsigned long readcharacter () { return readcharacter_mapping (False, False); } /* readcharacter_mapped () reads one character keyboard mapping is enabled */ unsigned long readcharacter_mapped () { return readcharacter_mapping (True, False); } /* readcharacter_unicode () reads one Unicode character keyboard mapping is suppressed */ unsigned long readcharacter_unicode () { return readcharacter_mapping (False, True); } /* readcharacter_unicode_mapped () reads one Unicode character keyboard mapping is enabled */ unsigned long readcharacter_unicode_mapped () { return readcharacter_mapping (True, True); } /*-------------------------------------------------------------------------*/ /* * DIRECT...getxy () reads in the information part of a cursor escape sequence */ static void DIRECTxtermgetxy (code) char code; /* 'M' for normal mouse report, 't'/'T' for tracking */ { character button; int xpos; int ypos; char track [22]; /* for mouse hilite tracking */ mouse_lastbutton = mouse_button; if (mouse_button == leftbutton || mouse_button == rightbutton || mouse_button == middlebutton) { mouse_prevbutton = mouse_button; } mouse_lastxpos = mouse_xpos; mouse_lastypos = mouse_ypos; if (code == 't') { mouse_button = releasebutton; } else if (code == 'T') { /* could be Siemens 97801/97808 page down ... !?! */ button = _readchar_nokeymap (); button = _readchar_nokeymap (); button = _readchar_nokeymap (); button = _readchar_nokeymap (); mouse_button = releasebutton; } else { /* code == 'M' */ button = _readchar_nokeymap (); if (button == quit_char) { quit = True; } button -= 32; mouse_shift = button & 0x1C; if (button & 32) { mouse_button = movebutton; } else if (button & 64) { button &= 0x03; if (button == 0x00) { mouse_button = wheelup; } else { mouse_button = wheeldown; } } else { button &= 0x03; if (button == 0x00) { mouse_button = leftbutton; } else if (button == 0x01) { mouse_button = middlebutton; } else if (button == 0x02) { mouse_button = rightbutton; } else { mouse_button = releasebutton; } } } xpos = _readchar_nokeymap (); if (xpos == quit_char) { quit = True; } mouse_xpos = xpos - 33; ypos = _readchar_nokeymap (); if (ypos == quit_char) { quit = True; } mouse_ypos = ypos - 33 - MENU; if (mouse_hilite_tracking && mouse_button == leftbutton) { /* handle hilite tracking */ if (mouse_ypos < 0 || mouse_ypos > last_y || (mouse_xpos == XMAX && disp_scrollbar) || is_menu_open ()) { /* abort hilite tracking */ #ifdef debug_hilite_tracking printf ("aborting hilite tracking\n"); #endif putescape ("\033[0;0;0;0;0T"); flush (); } else { #ifdef debug_hilite_tracking printf ("initiating hilite tracking\n"); #endif build_string (track, "\033[1;%d;%d;%d;%dT", mouse_xpos + 1, mouse_ypos + 1 + MENU, 1 + MENU, last_y + 3); putescape (track); flush (); } } } static void DIRECTcrttoolgetxy () { character c; int xpos; int ypos; mouse_lastbutton = mouse_button; if (mouse_button == leftbutton || mouse_button == rightbutton || mouse_button == middlebutton) { mouse_prevbutton = mouse_button; } mouse_lastxpos = mouse_xpos; mouse_lastypos = mouse_ypos; c = get_digits (& ypos); /* c should be ';' */ c = get_digits (& xpos); if (c == 'l') { mouse_button = leftbutton; } else if (c == 'm') { mouse_button = middlebutton; } else if (c == 'r') { mouse_button = rightbutton; } else { mouse_button = releasebutton; } mouse_ypos = ypos - 1 - MENU; mouse_xpos = xpos - 1; } /* * DIRECT... () reads in a direct cursor movement input sequence. * Then it either performs a direct function (move/copy/paste) or * invokes the menu functions. * Is no longer called as this is already handled in _readchar (). */ void DIRECTxterm () { DIRECTxtermgetxy ('M'); MOUSEescape (); } void TRACKxterm () { DIRECTxtermgetxy ('t'); MOUSEescape (); } void TRACKxtermT () { DIRECTxtermgetxy ('T'); MOUSEescape (); } void DIRECTcrttool () { DIRECTcrttoolgetxy (); MOUSEescape (); } #ifdef CURSES #ifdef KEY_MOUSE #ifdef __PDCURSES__ /* * CURSgetxy () reads in the information of a mouse event */ static void CURSgetxy () { # define mouse_state Mouse_status.changes # define mouse_x MOUSE_X_POS # define mouse_y MOUSE_Y_POS int button = 0; mouse_lastbutton = mouse_button; if (mouse_button == leftbutton || mouse_button == rightbutton || mouse_button == middlebutton) { mouse_prevbutton = mouse_button; } mouse_lastxpos = mouse_xpos; mouse_lastypos = mouse_ypos; request_mouse_pos (); if (BUTTON_CHANGED (1)) { button = 1; } else if (BUTTON_CHANGED (2)) { button = 2; } else if (BUTTON_CHANGED (3)) { button = 3; } #ifdef BUTTON_SHIFT mouse_shift = (BUTTON_STATUS (button) & BUTTON_MODIFIER_MASK) == BUTTON_SHIFT; #else mouse_shift = 0; #endif if ((BUTTON_STATUS (button) & BUTTON_ACTION_MASK) == BUTTON_PRESSED) { if (button == 1) { mouse_button = leftbutton; } else if (button == 2) { mouse_button = middlebutton; } else if (button == 3) { mouse_button = rightbutton; } else { mouse_button = releasebutton; } } else { mouse_button = releasebutton; } mouse_xpos = mouse_x; mouse_ypos = mouse_y - MENU; } # else static void CURSgetxy () { #ifdef NCURSES_VERSION MEVENT mouse_info; # define mouse_state mouse_info.bstate # define mouse_x mouse_info.x # define mouse_y mouse_info.y #else unsigned long mouse_state; # define mouse_x Mouse_status.x # define mouse_y Mouse_status.y #endif mouse_lastbutton = mouse_button; if (mouse_button == leftbutton || mouse_button == rightbutton || mouse_button == middlebutton) { mouse_prevbutton = mouse_button; } mouse_lastxpos = mouse_xpos; mouse_lastypos = mouse_ypos; #ifdef NCURSES_VERSION getmouse (& mouse_info); #else mouse_state = getmouse (); #endif #ifdef BUTTON_SHIFT mouse_shift = mouse_state & BUTTON_SHIFT; #else mouse_shift = 0; #endif if (mouse_state & BUTTON1_CLICKED) { mouse_button = leftbutton; } else if (mouse_state & BUTTON2_CLICKED) { mouse_button = middlebutton; } else if (mouse_state & BUTTON3_CLICKED) { mouse_button = rightbutton; } else { mouse_button = releasebutton; } mouse_xpos = mouse_x - 1; mouse_ypos = mouse_y - 1 - MENU; } #endif #endif #endif /*-------------------------------------------------------------------------*/ #ifndef msdos /* max. length of function key sequence to be detected (depending on the fkeymap table, approx. 7), or of keyboard mapping sequence plus potential mapping rest */ #define MAXCODELEN 33 /* * queue collects the keys of an Escape sequence typed in until the * sequence can be detected or rejected. * If the queue is not empty, queue [0] contains the character next * to be delivered by _readchar () (it's not a ring buffer). * The queue contents are always terminated by a '\0', so queue can also * be taken as a character string. */ static character queue [MAXCODELEN + 1], * endp = queue; static character ctrl_queue [MAXCODELEN + 1], * endcp = ctrl_queue; #ifdef not_used static int q_empty () { return endp == queue ? 1 : 0; } #endif static int q_notfull () { return endp - queue == MAXCODELEN ? 0 : 1; } static void q_clear () { endp = queue; endcp = ctrl_queue; } static int q_len () { return endp - queue; } static void q_put (c) character c; /* queue must not be full prior to this call! */ { * endp = c; * ++ endp = '\0'; if (c == '\0') { * endcp = '@'; } else { * endcp = c; } * ++ endcp = '\0'; } /* static character q_unput () { character c; if (q_len () == 0) { return '\0'; } else { endp --; endcp --; c = * endp; * endp = '\0'; * endcp = '\0'; return c; } } */ static character q_get () { character c; register character * pd; register character * ps; c = * queue; pd = queue; ps = pd + 1; while (ps <= endp) { * pd ++ = * ps ++; } if (endp > queue) { endp --; endcp --; } #define dont_debug_queue_delivery #ifdef debug_queue_delivery printf ("%02X\n", c); #endif return c; } /* * Look up key sequence in fkeymap table. * if matchmode == 0: * findkey (str) >= 0: escape sequence found * (str == fkeymap [findkey (str)].fk) * keyproc = fkeymap [i].fp (side effect) * == -1: escape sequence prefix recognised * (str is prefix of some entry in fkeymap) * == -2: escape sequence not found * (str is not contained in fkeymap) * * found == index of exact match if found * if matchmode == 1 (not used): * return -1 if any prefix detected (even if other exact match found) * if matchmode == 2 (not used): * don't return -1, only report exact or no match */ static int findkeyin (str, fkeymap, matchmode, found) char * str; struct fkeyentry * fkeymap; int matchmode; int * found; { int lastmatch = 0; /* last index with string matching prefix */ register int i; int ret = -2; * found = -1; if (fkeymap [0].fk == NIL_PTR) { return ret; } i = lastmatch; do { char * strpoi = str; char * mappoi = fkeymap [i].fk; do { /* compare str with map entry */ if (* strpoi != * mappoi) { break; } if (* strpoi) { strpoi ++; mappoi ++; } } while (* strpoi); /* if (strncmp (str, fkeymap [i].fk, strlen (str)) == 0) {*/ if (* strpoi == '\0') { /* str is prefix of current entry */ lastmatch = i; /* if (strlen (str) == strlen (fkeymap [i].fk)) {*/ if (* mappoi == '\0') { /* str is equal to current entry */ * found = i; keyproc = fkeymap [i].fp; if (! keyproc) { keyproc = I; } fkeyshift = fkeymap [i].fkeyshift; if (matchmode == 1) { /* return index unless other prefix was or will be found */ if (ret == -2) { ret = i; } } else { return i; } } else { /* str is partial prefix of current entry */ if (matchmode == 1) { /* return -1 but continue to search for exact match */ ret = -1; } else if (matchmode != 2) { return -1; } else { } } } ++ i; if (fkeymap [i].fk == NIL_PTR) { i = 0; return ret; } } while (i != lastmatch); return ret; } static int findkey (str) char * str; { int dummy; int res = findkeyin (str, fkeymap_terminfo, 0, & dummy); if (res != -2) { return res; } res = findkeyin (str, fkeymap_spec, 0, & dummy); if (res != -2) { return res; } return findkeyin (str, fkeymap, 0, & dummy); } /* Look up key sequence in keyboard mapping table. Similar to findkeyin but with modified parameter details. * if matchmode == 0 (not used): * mapkb (str) >= 0: key sequence str found * * mapped set to mapped string * == -1: key sequence prefix recognised * (str is prefix of some table entry) * == -2: key sequence not found * (str is not contained in table) * * found == index of exact match if found * if matchmode == 1: * return -1 if any prefix detected (even if other exact match found) * if matchmode == 2: * don't return -1, only report exact or no match */ static int mapkb (str, kbmap, matchmode, found, mapped) char * str; keymaptabletype kbmap; int matchmode; char * * found; char * * mapped; { #ifdef keymapping_stringtables int lastmatch = 0; /* last index with string matching prefix */ register int i; int ret = -2; int len = strlen (str); * found = NIL_PTR; if (* kbmap == '\0') { return ret; } i = lastmatch; do { if (strncmp (str, kbmap, len) == 0) { /* str is prefix of current entry */ lastmatch = i; if (len == strlen (kbmap)) { /* str is equal to current entry */ * found = kbmap; * mapped = kbmap + len + 1; if (matchmode == 1) { /* return index unless other prefix was or will be found */ if (ret == -2) { ret = i; } } else { return i; } } else { /* str is partial prefix of current entry */ if (matchmode == 1) { /* return -1 but continue to search for exact match */ ret = -1; } else if (matchmode != 2) { return -1; } else { } } } ++ i; kbmap += strlen (kbmap) + 1; kbmap += strlen (kbmap) + 1; if (* kbmap == '\0') { i = 0; return ret; } } while (i != lastmatch); return ret; #else int lastmatch = 0; /* last index with string matching prefix */ register int i; int ret = -2; * found = NIL_PTR; if (kbmap [0].fk == NIL_PTR) { return ret; } i = lastmatch; do { if (strncmp (str, kbmap [i].fk, strlen (str)) == 0) { /* str is prefix of current entry */ lastmatch = i; if (strlen (str) == strlen (kbmap [i].fk)) { /* str is equal to current entry */ * found = kbmap [i].fk; * mapped = kbmap [i].fp; if (! * mapped) { * mapped = I; } if (matchmode == 1) { /* return index unless other prefix was or will be found */ if (ret == -2) { ret = i; } } else { return i; } } else { /* str is partial prefix of current entry */ if (matchmode == 1) { /* return -1 but continue to search for exact match */ ret = -1; } else if (matchmode != 2) { return -1; } else { } } } ++ i; if (kbmap [i].fk == NIL_PTR) { i = 0; return ret; } } while (i != lastmatch); return ret; #endif } #endif /* ifndef msdos */ #ifdef CURSES chtype key; extern int curs_readchar _((void)); static void showfkey () { build_string (text_buffer, "Curses function key entered: %03X / %04o", key, key); status_msg (text_buffer); } /* * Read a character, ignoring uninterpreted key strokes (SHIFT etc.) * also handles resize events */ int curs_readchar () { unsigned long keycode; keycode = __readchar (); while (keycode >= KEY_MIN) { switch (keycode) { #ifdef KEY_RESIZE case KEY_RESIZE: printf ("curses resize key received \n"); sleep (1); keyproc = showfkey; return FUNcmd; #endif #ifdef KEY_SHIFT_L case KEY_SHIFT_L: case KEY_SHIFT_R: case KEY_CONTROL_L: case KEY_CONTROL_R: case KEY_ALT_L: case KEY_ALT_R: break; #endif default: return keycode; } keycode = __readchar (); } return keycode; } /* * Mapping KEY_ code (curses) -> mined function */ struct { chtype keycode; voidfunc func; unsigned char fkeyshift; } cursfunc [] = { {KEY_F(1), F1}, {KEY_F(2), F2}, {KEY_F(3), F3}, {KEY_F(4), F4}, {KEY_F(5), F5}, {KEY_F(6), F6}, {KEY_F(7), F7}, {KEY_F(8), F8}, {KEY_F(9), F9}, {KEY_F(10), F10}, {KEY_F(11), F11}, {KEY_F(12), F12}, {KEY_IC, INSkey}, {KEY_DC, DELkey}, {KEY_HOME, HOMEkey}, {KEY_END, ENDkey}, {KEY_PPAGE, PU}, {KEY_NPAGE, PD}, {KEY_UP, MUP}, {KEY_DOWN, MDN}, {KEY_LEFT, MLF}, {KEY_RIGHT, MRT}, #ifdef KEY_A2 {KEY_A2, MUP}, #endif #ifdef KEY_C2 {KEY_C2, MDN}, #endif #ifdef KEY_B1 {KEY_B1, MLF}, #endif #ifdef KEY_B3 {KEY_B3, MRT}, #endif {KEY_B2, HOP}, {KEY_A1, HOMEkey}, {KEY_A3, PU}, {KEY_C1, ENDkey}, {KEY_C3, PD}, {0x1BF, BLINE}, {0x1C0, ELINE}, #ifdef PAD0 {PAD0, PASTE}, #endif #ifdef __PDCURSES__ {PADSLASH, I}, {PADSTAR, I}, {PADMINUS, I}, {PADPLUS, I}, {PADSTOP, CUT}, {PADENTER, SNL}, {ALT_F, FILEMENU}, {ALT_E, EDITMENU}, {ALT_S, SEARCHMENU}, {ALT_P, PARAMENU}, {ALT_O, OPTIONSMENU}, #endif {0} }; /* * Look up mined function by curses key code * lookup_curskey (str) >= 0: keycode == cursfunc [lookup_curskey (str)].fk * == -1: keycode is not contained in mapping table */ static voidfunc lookup_curskey (keycode) chtype keycode; { register int i; i = 0; while (cursfunc [i].keycode != 0 && cursfunc [i].keycode != keycode) { i ++; } if (cursfunc [i].keycode == 0) { return showfkey; } else { keyshift |= cursfunc [i].fkeyshift; return cursfunc [i].func; } } #endif /* * Functions to read a character from terminal. If _readchar () detects a function key sequence (according to the table fkeymap), FUNcmd is returned, and the associated function is stored in the variable keyproc. Keyboard mapping is applied. */ unsigned long _readchar_nokeymap () { unsigned long c; int prev_dont_suppress_keymap = dont_suppress_keymap; dont_suppress_keymap = 0; c = _readchar (); dont_suppress_keymap = prev_dont_suppress_keymap; return c; } #ifndef msdos static int choose_char _((char *)); static character rest_queue [MAXCODELEN + 1]; static FLAG have_rest_queue = False; static void putback_rest (rest) char * rest; { char old_rest_queue [MAXCODELEN + 1]; if (! streq (rest, " ")) { if (have_rest_queue) { /** overdraft characters to be mapped are put back into rest_queue to be considered for subsequent mapping -> Hiragana nihongo -> Hiragana nyi -> test abcde */ strcpy (old_rest_queue, (char *) rest_queue); } else { old_rest_queue [0] = '\0'; } strcpy ((char *) rest_queue, rest); strcat ((char *) rest_queue, old_rest_queue); have_rest_queue = True; } } #endif /* read 1 byte from queue; for curses, however, function key indications must be passed on which are longer than 8 bits */ int read1byte () { #ifndef msdos character ch; character * cr; if (have_rest_queue) { ch = * rest_queue; cr = rest_queue; while (* (cr + 1) != '\0') { * cr = * (cr + 1); cr ++; } * cr = '\0'; if (* rest_queue == '\0') { have_rest_queue = False; } return ch; } else #endif { #ifdef CURSES return curs_readchar (); #else if (report_winchg) { return __readchar_report_winchg (); } else { return __readchar (); } #endif } } #ifndef msdos static int bytereadyafter (msec) int msec; { return have_rest_queue || inputreadyafter (input_fd, msec); } /* * Is a character available within a specified number of milliseconds ? */ int char_ready_within (msec) int msec; { return (q_len () > 0) || bytereadyafter (msec); } #else /* ifndef msdos */ int char_ready_within (msec) int msec; { return inputreadyafter (input_fd, msec); } #endif #ifndef msdos #define radical_stroke #endif #ifdef radical_stroke static menuitemtype radicalsmenu [] = { /* 1 stroke radicals */ {"①-1:一 2:丨 3:丶 4:丿乀乁 5:乙乚乛 6:亅", dummyfunc, ""}, /* 2 strokes radicals */ {"②-7:二 8:亠 9:人亻 10:儿 11:入 12:八 13:冂 14:冖", dummyfunc, ""}, {"②-15:冫 16:几 17:凵 18:刀刁刂 19:力 20:勹 21:匕", dummyfunc, ""}, {"②-22:匚 23:匸 24:十 25:卜 26:卩 27:厂 28:厶 29:又", dummyfunc, ""}, /* 3 strokes radicals */ {"③-30:口 31:囗 32:土 33:士 34:夂 35:夊 36:夕 37:大夨 38:女 39:子孑孒孓", dummyfunc, ""}, {"③-40:宀 41:寸 42:小 43:尢尣 44:尸 45:屮 46:山 47:巛巜川 48:工 49:己已巳", dummyfunc, ""}, {"③-50:巾 51:干 52:乡幺 53:广 54:廴 55:廾 56:弋 57:弓 58:彐彑 59:彡 60:彳", dummyfunc, ""}, /* 4 strokes radicals */ {"④-61:心忄 62:戈 63:戶户戸 64:手扌才 65:支 66:攴攵 67:文 68:斗", dummyfunc, ""}, {"④-69:斤 70:方 71:无 72:日 73:曰 74:月 75:木朩 76:欠 77:止 78:歹 79:殳", dummyfunc, ""}, {"④-80:毋毌 81:比 82:毛 83:氏 84:气 85:水氵 86:火灬 87:爪爫 88:父 89:爻", dummyfunc, ""}, {"④-90:丬爿 91:片 92:牙㸦 93:牛牜 94:犬犭", dummyfunc, ""}, /* 5 strokes radicals */ {"⑤-95:玄 96:玉王 97:瓜 98:瓦 99:甘 100:生 101:用甩 102:田由甲申甴电", dummyfunc, ""}, {"⑤-103:疋 104:疒 105:癶 106:白 107:皮 108:皿 109:目", dummyfunc, ""}, {"⑤-110:矛 111:矢 112:石 113:示礻 114:禸 115:禾 116:穴 117:立", dummyfunc, ""}, /* 6 strokes radicals */ {"⑥-118:竹 119:米 120:糸糹纟 121:缶 122:网罒罓䍏 123:羊 124:羽 125:老耂考", dummyfunc, ""}, {"⑥-126:而 127:耒 128:耳 129:聿肀 130:肉 131:臣 132:自", dummyfunc, ""}, {"⑥-133:至 134:臼 135:舌 136:舛 137:舟 138:艮 139:色 140:艸艹䒑", dummyfunc, ""}, {"⑥-141:虍 142:虫 143:血 144:行 145:衣衤 146:襾西覀", dummyfunc, ""}, /* 7 strokes radicals */ {"⑦-147:見见 148:角 149:言訁讠 150:谷 151:豆 152:豕 153:豸", dummyfunc, ""}, {"⑦-154:貝贝 155:赤 156:走赱 157:足 158:身 159:車车 160:辛", dummyfunc, ""}, {"⑦-161:辰 162:辵辶 163:邑 164:酉 165:釆 166:里", dummyfunc, ""}, /* 8 strokes radicals */ {"⑧-167:金釒钅 168:長镸长 169:門门 170:阜阝", dummyfunc, ""}, {"⑧-171:隶 172:隹 173:雨 174:靑青 175:非", dummyfunc, ""}, /* 9 strokes radicals */ {"⑨-176:面靣 177:革 178:韋韦 179:韭 180:音 181:頁页", dummyfunc, ""}, {"⑨-182:風风 183:飛飞 184:食飠饣 185:首 186:香", dummyfunc, ""}, /* 10 strokes radicals */ {"⑩-187:馬马 188:骨 189:高髙 190:髟 191:鬥 192:鬯 193:鬲 194:鬼", dummyfunc, ""}, /* 11 strokes radicals */ {"⑪-195:魚鱼 196:鳥鸟 197:鹵 198:鹿 199:麥麦 200:麻", dummyfunc, ""}, /* 12 strokes radicals */ {"⑫-201:黃黄 202:黍 203:黑黒 204:黹", dummyfunc, ""}, /* 13 strokes radicals */ {"⑬-205:黽黾 206:鼎 207:鼓鼔 208:鼠鼡", dummyfunc, ""}, /* 14 strokes radicals */ {"⑭-209:鼻 210:齊齐", dummyfunc, ""}, /* 15 strokes radicals */ {"⑮-211:齒齿", dummyfunc, ""}, /* 16 strokes radicals */ {"⑯-212:龍龙 213:龜龟", dummyfunc, ""}, /* 17 strokes radical */ {"⑰-214:龠", dummyfunc, ""}, }; #endif #define dont_debug_kbesc #define dont_debug_kbmap static unsigned long _readchar () { unsigned long ch; #ifndef msdos int res; char * found; char * mapped; char * prev_found = NIL_PTR; #endif char * choice; int choice_index; if (escape_delay == 0 || keymap_delay == 0) { char * env = getenv ("ESCDELAY"); if (env) { (void) scan_int (env, & escape_delay); } if (escape_delay == 0) { escape_delay = default_escape_delay; } env = getenv ("MAPDELAY"); if (env) { (void) scan_int (env, & keymap_delay); } if (keymap_delay == 0) { keymap_delay = default_keymap_delay; } } #ifndef msdos if (q_len () > 0) { return q_get (); } queue_mode_mapped = False; #endif keyshift = 0; #ifdef radical_stroke /* plug-in specific input methods */ if (allow_keymap && dont_suppress_keymap && streq (keyboard_mapping, "rs") ) { int choice_col = x; int choice_line = y + 1; char radicalnumber [4]; choice_index = -1; /* adjust menu position if too far down */ if (choice_line + arrlen (radicalsmenu) + 2 > YMAX) { choice_line = y - arrlen (radicalsmenu) - 2; if (choice_line < 0) { choice_line = 0; } } /* adjust menu position if on status line */ if (in_status_line) { choice_line = YMAX - arrlen (radicalsmenu) - 2; if (choice_line < 0) { choice_line = 0; } choice_col = lpos; } /* try to get radical, then character, from user */ while (choice_index < 0) { int radical = popup_menu (radicalsmenu, arrlen (radicalsmenu), choice_col, choice_line, "Select radical", False, False, "1234567890x"); if (radical < 0) { /* revert to previous mapping (or none) */ toggleKEYMAP (); set_cursor_xy (); flush (); choice_index = 0; /* continue */ } else { int radical_row = radical / 11; int radical_col = radical % 11; mapped = radicalsmenu [radical_row].itemname; while (* mapped != '\0' && (* mapped < '0' || * mapped > '9' || radical_col > 0)) { if (* mapped == ':') { radical_col --; } mapped ++; } found = radicalnumber; while (* mapped >= '0' && * mapped <= '9') { * found ++ = * mapped ++; } * found = '\0'; res = mapkb (radicalnumber, keyboard_map, 2, & found, & mapped); if (res >= 0) { /* first goto in my life and then such an exceptionally ugly one - but it works well just this way */ goto handle_mapped; } else { ring_bell (); } } } } #endif #ifdef CURSES key = read1byte (); if (key >= KEY_MIN) { #ifdef KEY_MOUSE if (key == KEY_MOUSE) { CURSgetxy (); keyproc = MOUSEescape; return FUNcmd; } #endif keyproc = lookup_curskey (key); return FUNcmd; } ch = key; #else /* ifdef CURSES */ #ifdef dosmouse { int ich = __readchar (); if (ich < 0) { DIRECTdosmousegetxy (); keyproc = MOUSEescape; return FUNcmd; } else { ch = ich; } } #else ch = read1byte (); if (ch == FUNcmd) { /* pass back WINCH exception */ return FUNcmd; } #endif #endif /* else CURSES */ #ifdef msdos if (ch == '\000') { # ifdef dosmouse ch = getch (); # else ch = read1byte (); # endif keyproc = pc_fkey_map [ch].fp; if (! keyproc) { keyproc = I; } keyshift = pc_fkey_map [ch].fkeyshift; # ifdef debug_whatever if ((voidfunc) keyproc == (voidfunc) I) { return ch; } /* (voidfunc) is an identity cast here. It seems to be required for the sake of the apparently totally rotten microvax compiler */ # endif return FUNcmd; } else { return ch; } #else if (ch == '\033') { char second_esc_char = '\0'; q_put (ch); while ((res = findkey (ctrl_queue)) == -1 /* prefix of table entry */ && q_notfull () && bytereadyafter (escape_delay) ) { char prev_ch = ch; ch = read1byte (); #ifdef debug_kbesc printf ("<^[%s> + [%dms] %02X\n", ctrl_queue + 1, escape_delay, ch); #endif /* accept ESC prefix as Alt modifier */ if (detect_esc_alt && ch == '\033' && prev_ch == '\033') { if (bytereadyafter (escape_delay)) { ch = read1byte (); keyshift |= alt_mask; #ifdef debug_kbesc printf ("-> <^[%s> + ^[/%02X\n", ctrl_queue + 1, ch); #endif } } /* accept XTerm*modifyCursorKeys: 3 as well as device attributes reports (primary/secondary DA) */ if (second_esc_char == '[' && prev_ch == '[' && (ch == '>' || ch == '?') ) { if (ch == '?') { keyshift |= report_mask; } ch = read1byte (); #ifdef debug_kbesc printf ("-> <^[%s> + >?/%02X\n", ctrl_queue + 1, ch); #endif } check_ctrl_byte: /* handle generic shift state of ANSI sequences: */ if (ch == ';' && second_esc_char == '[') { ch = read1byte (); if (ch >= '2' && ch <= '8') { /* ESC [1;2A -> ESC [1A + shift etc */ keyshift |= (ch & ~'0') - 1; } else if (ch == '1') { ch = read1byte (); if (ch >= '0' && ch <= '6') { /* xterm with alwaysUseMods: */ /* ESC [1;11A -> ESC [1A + alt etc */ keyshift |= applkeypad_mask | ((ch & ~'0') + 1); } else { q_put (';'); q_put ('1'); q_put (ch); } } else { q_put (';'); q_put (ch); } ch = read1byte (); #ifdef debug_kbesc printf ("-> <^[%s> + 1-8/%02X\n", ctrl_queue + 1, ch); #endif } else if (ch == ';' && second_esc_char == '1') { ch = read1byte (); if (ch >= '2' && ch <= '8') { /* xterm/VT52 mode: ESC 1;2A -> ESC 1A + shift etc */ keyshift |= (ch & ~'0') - 1; } else { q_put (';'); q_put (ch); } ch = read1byte (); #ifdef debug_kbesc printf ("-> <^[%s> + ;/%02X\n", ctrl_queue + 1, ch); #endif } else if (ch >= '0' && ch <= '9' && (second_esc_char == 'O' || (hp_shift_mode && ! second_esc_char))) { if (ch >= '2' && ch <= '8') { /* ESC O2A -> ESC OA + shift etc */ /* HP: ESC 2p -> ESC p + shift etc */ keyshift |= (ch & ~'0') - 1; } else if (ch == '1') { ch = read1byte (); if (ch >= '0' && ch <= '6') { /* ESC O11P -> ESC OP + alt etc */ /* HP: ESC 11p -> ESC p + alt etc */ keyshift |= applkeypad_mask | ((ch & ~'0') + 1); } else { q_put ('1'); q_put (ch); } } else { q_put (ch); } ch = read1byte (); #ifdef debug_kbesc printf ("-> <^[%s> + 0-9/%02X\n", ctrl_queue + 1, ch); #endif } else if (sco_shift_mode && second_esc_char == '[' && ch >= '0' && ch <= '9') { char newkeyshift; char newch = '\0'; if (ch >= '2' && ch <= '8') { /* SCO: ESC [2M -> ESC [M + shift etc */ newkeyshift = (ch & ~'0') - 1; newch = read1byte (); #ifdef debug_kbesc printf ("-> <^[%s> + 2-8/%02X\n", ctrl_queue + 1, newch); #endif if (newch >= 'A' && newch <= 'Z') { keyshift |= newkeyshift; } else { q_put (ch); } } else if (ch == '1') { ch = read1byte (); #ifdef debug_kbesc printf ("-> <^[%s> + 1/%02X\n", ctrl_queue + 1, ch); #endif if (ch >= '0' && ch <= '6') { /* SCO: ESC [11M -> ESC [M + alt etc */ newkeyshift = applkeypad_mask | ((ch & ~'0') + 1); newch = read1byte (); if (newch >= 'A' && newch <= 'Z') { keyshift |= newkeyshift; } else { q_put ('1'); q_put (ch); } } else if (ch == ';') { /* xterm SCO: ESC [1;5R -> ESC [R + alt etc */ ch = read1byte (); keyshift |= (ch & ~'0') - 1; newch = read1byte (); } else { q_put ('1'); q_put (ch); newch = read1byte (); } } else { #ifdef debug_kbesc printf ("-> <^[%s>\n", ctrl_queue + 1); #endif q_put (ch); newch = read1byte (); } ch = newch; if (ch == ';') { /* OK, so here is my second goto; this is really a very peculiar case, based on misconfiguration (mined assumes sco, terminal sends modified xterm sequences), which does not deserve any goto avoidance effort */ #ifdef debug_kbesc printf ("GOTO check_ctrl_byte\n"); #endif goto check_ctrl_byte; } } else if (prev_ch >= '0' && prev_ch <= '9') { if (ch == '^') { /* ESC [5^ -> ESC [5~ + control (rxvt) */ keyshift |= ctrl_mask; ch = '~'; } else if (ch == '$') { /* ESC [5$ -> ESC [5~ + shift (rxvt) */ keyshift |= shift_mask; ch = '~'; } else if (ch == '@') { /* ESC [5@ -> ESC [5~ + control+shift (rxvt) */ keyshift |= ctrlshift_mask; ch = '~'; } } else if (ch >= 'a' && ch <= 'd') { if (prev_ch == 'O') { /* ESC Oa -> ESC OA + control (rxvt) */ keyshift |= ctrl_mask; ch -= 'a' - 'A'; } else if (prev_ch == '[') { /* ESC [a -> ESC [A + shift (rxvt) */ keyshift |= shift_mask; ch -= 'a' - 'A'; } } q_put (ch); if (second_esc_char == '\0') { second_esc_char = ch; if (second_esc_char == 'O') { keyshift |= applkeypad_mask; } } } #ifdef debug_kbesc printf ("=> [%d] <^[%s> [keyshift %X]\n", res, ctrl_queue + 1, keyshift); #endif if (quit) { keyproc = I; return FUNcmd; } else if (res < 0) { /* key pattern not found in fkeymap table */ if (second_esc_char == '[') { /* generic scanning for unknown ANSI sequence */ (void) q_get (); /* swallow ESC */ (void) q_get (); /* swallow [ */ putback_rest (ctrl_queue + 2); ansi_params = 0; do { int i; ansi_fini = get_digits (& i); if (ansi_params < max_ansi_params) { ansi_param [ansi_params] = i; ansi_params ++; } } while (ansi_fini == ';'); q_clear (); if (ansi_params >= 3 && ansi_param [0] == 27 && ansi_fini == '~') { /* handle generic escape sequence for modified key (xterm 214 resource modifyOtherKeys) */ if (ansi_param [1] > 8) { ansi_param [1] -= 8; } keyshift |= ansi_param [1] - 1; /* enforce UTF-8 interpretation of input */ queue_mode_mapped = True; if (ansi_param [2] == ' ' && (keyshift & ctrlshift_mask) == ctrl_mask) { /* map ctrl-space to MARK, alt-ctrl-space to Hop MARK */ q_put ('\0'); } else if (ansi_param [2] == 0) { q_put ('\0'); } else { char cbuf [7]; char * cp = cbuf; /* Shift-a/A -> A */ if ((keyshift & altctrlshift_mask) == shift_mask && isLetter (ansi_param [2]) ) { keyshift = 0; ansi_param [2] = case_convert (ansi_param [2], 1); } /* Control-/ etc as accent prefix */ if (keyshift & ctrl_mask) { struct prefixspec * ps; ps = lookup_prefix (COMPOSE, ansi_param [2]); if (ps && * ps->accentname) { keyshift = ansi_param [2]; keyproc = COMPOSE; return FUNcmd; } else if (ps) { unsigned long unichar; int len; utf8_info (ps->pat1, & len, & unichar); ansi_param [2] = unichar; } else if ('?' <= ansi_param [2] && ansi_param [2] < '') { keyshift &= ~ ctrl_mask; return ansi_param [2] & 0x1F; } } (void) utfencode (ansi_param [2], cbuf); while (* cp) { q_put (* cp ++); } } /* Control/Alt/Control-Alt-0 -> ...key_0 */ if (ansi_param [2] >= '0' && ansi_param [2] <= '9') { switch (ansi_param [2]) { case '0': keyproc = key_0; break; case '1': keyproc = key_1; break; case '2': keyproc = key_2; break; case '3': keyproc = key_3; break; case '4': keyproc = key_4; break; case '5': keyproc = key_5; break; case '6': keyproc = key_6; break; case '7': keyproc = key_7; break; case '8': keyproc = key_8; break; case '9': keyproc = key_9; break; } q_clear (); return FUNcmd; } if (keyshift & alt_mask) { /* 2000.13 workaround for prompt */ if ((keyshift & altctrl_mask) == alt_mask) { if (ansi_param [2] == 'k') { q_clear (); keyproc = toggleKEYMAP; return FUNcmd; } if (ansi_param [2] == 'K' || ansi_param [2] == 'I') { q_clear (); keyproc = setupKEYMAP; return FUNcmd; } } return '\033'; } else if (keyshift) { return q_get (); } else { /* fall through to keyboard mapping */ } } else { /* not CSI 27 sequence */ keyproc = ANSIseq; return FUNcmd; } } else if (keyshift & alt_mask) { /* restore the previously filtered ESCAPE */ return '\033'; } else { /* just deliver the typed characters */ return q_get (); } } else { /* key pattern found in fkeymap table */ q_clear (); keyshift |= fkeyshift; if (keyproc == DIRECTxterm) { DIRECTxtermgetxy ('M'); keyproc = MOUSEescape; } else if (keyproc == TRACKxterm) { DIRECTxtermgetxy ('t'); keyproc = MOUSEescape; } else if (keyproc == TRACKxtermT) { DIRECTxtermgetxy ('T'); keyproc = MOUSEescape; } else if (keyproc == DIRECTcrttool) { DIRECTcrttoolgetxy (); keyproc = MOUSEescape; } return FUNcmd; } } else { q_put (ch); } if (allow_keymap && dont_suppress_keymap && keyboard_map != (keymaptabletype) NIL_PTR) { while ((res = mapkb (ctrl_queue, keyboard_map, 1, & found, & mapped)) == -1 /* prefix of some table entry */ && q_notfull () && bytereadyafter (keymap_delay) ) { q_put (read1byte ()); /* exact match found? note for later consideration */ if (found != NIL_PTR) { prev_found = found; } } /* possible results: res >= 0: match found, no further prefix match res == -1, prev_found != NIL_PTR: prefix with previous match res == -1: prefix only, no further key typed res == -2: no match with previous match */ #ifdef debug_kbmap printf ("mapping %s, res %d, found %s -> ", ctrl_queue, res, found); #endif if (res < 0 && prev_found != NIL_PTR) { res = 1; if (found == NIL_PTR) { #ifdef debug_kbmap printf ("rest %s, ", ctrl_queue + strlen (prev_found)); #endif putback_rest (ctrl_queue + strlen (prev_found)); } } else if (res == -1) { res = mapkb (ctrl_queue, keyboard_map, 2, & found, & mapped); #ifdef debug_kbmap printf ("find again %s, found %s, ", ctrl_queue, found); #endif } #ifdef debug_kbmap printf ("res %d\n", res); #endif if (res >= 0) { /* key pattern detected in key mapping table */ handle_mapped: q_clear (); /* check if mapping defines multiple choices */ while (* mapped == ' ') { mapped ++; } choice = strchr (mapped, ' '); while (choice != NIL_PTR && * choice == ' ') { choice ++; } if (choice != NIL_PTR && * choice != '\0') { choice_index = choose_char (mapped); #ifdef debug_kbmap printf (" choose_char (%s) -> %d\n", mapped, choice_index); #endif if (choice_index < 0) { mapped = NIL_PTR; /* mapping cancelled */ } else { while (choice_index > 0 && mapped != NIL_PTR && * mapped != '\0') { mapped = strchr (mapped, ' '); if (mapped != NIL_PTR) { while (* mapped == ' ') { mapped ++; } } choice_index --; } } } if (mapped != NIL_PTR) { queue_mode_mapped = True; while (* mapped != '\0' && * mapped != ' ') { q_put (* mapped); mapped ++; } } #ifdef debug_kbmap printf (" queued %s\n", ctrl_queue); #endif } if (q_len () > 0) { return q_get () /* deliver the first mapped byte */; } else { ring_bell (); flush (); /* clear key mapping menu */ return _readchar (); } } else { /* not keyboard mapped */ return q_get (); } #endif /* #ifdef msdos #else */ } #ifndef msdos #define dont_debug_choose_char static int choose_char (choices) char * choices; { int choice_count = 0; char * choicepoi = choices; int choice_col = x; int choice_line = y + 1; char * thischoiceline; char * choicelines; menuitemtype * choicemenu; int li, ci, lastcol, lastrow; char * choicelinepoi; int selected; #ifdef cut_picklist_to_screen FLAG reduced_menu = False; #endif /* count choices */ do { choice_count ++; choicepoi = strchr (choicepoi, ' '); while (choicepoi != NIL_PTR && * choicepoi == ' ') { choicepoi ++; } } while (choicepoi != NIL_PTR && * choicepoi != '\0'); #ifdef debug_choose_char printf ("choices <%s>\n", choices); printf ("choice_count %d\n", choice_count); #endif lastrow = (choice_count - 1) / 10; choicelines = alloc (strlen (choices) + 1 + choice_count * 2); choicemenu = alloc ((lastrow + 1) * sizeof (menuitemtype)); if (choicelines == NIL_PTR || choicemenu == (menuitemtype *) NIL_PTR) { if (choicelines != NIL_PTR) { free_space (choicelines); } ring_bell (); flush (); return -1; } /* adjust menu position if too far down */ if (choice_line + lastrow + 3 > YMAX) { choice_line = y - lastrow - 3; if (choice_line < 0) { choice_line = 0; } } /* adjust menu position if on status line */ if (in_status_line) { choice_line = YMAX - lastrow - 3; if (choice_line < 0) { choice_line = 0; } choice_col = lpos; } /* construct menu items */ choicepoi = choices; while (* choicepoi == ' ') { choicepoi ++; } thischoiceline = choicelines; for (li = 0; li <= lastrow; li ++) { /* construct menu line */ choicelinepoi = thischoiceline; if (li == lastrow) { lastcol = (choice_count - 1) % 10; } else { lastcol = 9; } for (ci = 0; ci <= lastcol; ci ++) { * choicelinepoi ++ = (ci + 1) % 10 + '0'; * choicelinepoi ++ = ':'; while (* choicepoi != ' ' && * choicepoi != '\0') { * choicelinepoi ++ = * choicepoi ++; } while (* choicepoi == ' ') { choicepoi ++; } if (ci < lastcol) { * choicelinepoi ++ = ' '; } } * choicelinepoi ++ = '\0'; /* add menu line to menu */ #ifdef debug_choose_char printf ("choiceline <%s>\n", thischoiceline); #endif /* fill menu item with collected data */ fill_menuitem (& choicemenu [li], thischoiceline); thischoiceline = choicelinepoi; } #ifdef debug_choose_char printf ("choicelines alloc %d length %d\n", strlen (choices) + 1 + choice_count * 2 + lastrow + 1, thischoiceline - choicelines); #endif #ifdef cut_picklist_to_screen if (lastrow >= YMAX - 2) { lastrow = YMAX - 3; reduced_menu = True; if (! in_status_line) { status_msg ("Warning: full menu too large to display"); } } #endif selected = popup_menu (choicemenu, lastrow + 1, choice_col, choice_line, "Choose character", False, False, "1234567890"); if (in_status_line) { redraw_prompt (); #ifdef cut_picklist_to_screen } else if (reduced_menu) { clear_status (); #endif } #ifdef debug_choose_char printf ("selected %d\n", selected); #endif free_space (choicemenu); free_space (choicelines); if (selected < choice_count) { return selected; } else { return -1; } } #endif /*======================================================================*\ |* End *| \*======================================================================*/