13941Svenki/*	$NetBSD: getch.c,v 1.79 2024/05/14 10:22:48 uwe Exp $	*/
23941Svenki
33941Svenki/*
43941Svenki * Copyright (c) 1981, 1993, 1994
53941Svenki *	The Regents of the University of California.  All rights reserved.
63941Svenki *
73941Svenki * Redistribution and use in source and binary forms, with or without
83941Svenki * modification, are permitted provided that the following conditions
93941Svenki * are met:
103941Svenki * 1. Redistributions of source code must retain the above copyright
113941Svenki *    notice, this list of conditions and the following disclaimer.
123941Svenki * 2. Redistributions in binary form must reproduce the above copyright
133941Svenki *    notice, this list of conditions and the following disclaimer in the
143941Svenki *    documentation and/or other materials provided with the distribution.
153941Svenki * 3. Neither the name of the University nor the names of its contributors
163941Svenki *    may be used to endorse or promote products derived from this software
173941Svenki *    without specific prior written permission.
183941Svenki *
193941Svenki * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
203941Svenki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
213941Svenki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
223941Svenki * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2311471SMichael.Bergknoff@Sun.COM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
243941Svenki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
253941Svenki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
263941Svenki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
273941Svenki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
283941Svenki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
293941Svenki * SUCH DAMAGE.
303941Svenki */
313941Svenki
323941Svenki#include <sys/cdefs.h>
333941Svenki#ifndef lint
343941Svenki#if 0
353941Svenkistatic char sccsid[] = "@(#)getch.c	8.2 (Berkeley) 5/4/94";
363941Svenki#else
373941Svenki__RCSID("$NetBSD: getch.c,v 1.79 2024/05/14 10:22:48 uwe Exp $");
383941Svenki#endif
393941Svenki#endif					/* not lint */
403941Svenki
413941Svenki#include <errno.h>
423941Svenki#include <string.h>
437746SKelly.Moyer@Sun.COM#include <stdlib.h>
4411471SMichael.Bergknoff@Sun.COM#include <unistd.h>
453941Svenki#include <stdio.h>
463941Svenki#include "curses.h"
473941Svenki#include "curses_private.h"
483941Svenki#include "keymap.h"
493941Svenki
503941Svenkishort _cursesi_state;		/* state of the inkey function */
513941Svenki
523941Svenkistatic const struct tcdata tc[] = {
533941Svenki	{TICODE_kSAV, KEY_SSAVE},
543941Svenki	{TICODE_kSPD, KEY_SSUSPEND},
553941Svenki	{TICODE_kUND, KEY_SUNDO},
563941Svenki	{TICODE_kHLP, KEY_SHELP},
573941Svenki	{TICODE_kHOM, KEY_SHOME},
583941Svenki	{TICODE_kIC, KEY_SIC},
593941Svenki	{TICODE_kLFT, KEY_SLEFT},
603941Svenki	{TICODE_krdo, KEY_REDO},
613941Svenki	{TICODE_khlp, KEY_HELP},
623941Svenki	{TICODE_kmrk, KEY_MARK},
633941Svenki	{TICODE_kmsg, KEY_MESSAGE},
643941Svenki	{TICODE_kmov, KEY_MOVE},
653941Svenki	{TICODE_knxt, KEY_NEXT},
663941Svenki	{TICODE_kopn, KEY_OPEN},
673941Svenki	{TICODE_kopt, KEY_OPTIONS},
683941Svenki	{TICODE_kprv, KEY_PREVIOUS},
693941Svenki	{TICODE_kprt, KEY_PRINT},
703941Svenki	{TICODE_kMSG, KEY_SMESSAGE},
713941Svenki	{TICODE_kMOV, KEY_SMOVE},
723941Svenki	{TICODE_kNXT, KEY_SNEXT},
733941Svenki	{TICODE_kOPT, KEY_SOPTIONS},
743941Svenki	{TICODE_kPRV, KEY_SPREVIOUS},
753941Svenki	{TICODE_kPRT, KEY_SPRINT},
763941Svenki	{TICODE_kRDO, KEY_SREDO},
773941Svenki	{TICODE_kRPL, KEY_SREPLACE},
783941Svenki	{TICODE_kRIT, KEY_SRIGHT},
793941Svenki	{TICODE_kRES, KEY_SRSUME},
803941Svenki	{TICODE_kCAN, KEY_SCANCEL},
813941Svenki	{TICODE_kref, KEY_REFERENCE},
823941Svenki	{TICODE_krfr, KEY_REFRESH},
833941Svenki	{TICODE_krpl, KEY_REPLACE},
843941Svenki	{TICODE_krst, KEY_RESTART},
853941Svenki	{TICODE_kres, KEY_RESUME},
863941Svenki	{TICODE_ksav, KEY_SAVE},
873941Svenki	{TICODE_kspd, KEY_SUSPEND},
883941Svenki	{TICODE_kund, KEY_UNDO},
893941Svenki	{TICODE_kBEG, KEY_SBEG},
905723Sfw157321	{TICODE_kFND, KEY_SFIND},
913941Svenki	{TICODE_kCMD, KEY_SCOMMAND},
923941Svenki	{TICODE_kCPY, KEY_SCOPY},
933941Svenki	{TICODE_kCRT, KEY_SCREATE},
943941Svenki	{TICODE_kDC, KEY_SDC},
953941Svenki	{TICODE_kDL, KEY_SDL},
963941Svenki	{TICODE_kslt, KEY_SELECT},
973941Svenki	{TICODE_kEND, KEY_SEND},
983941Svenki	{TICODE_kEOL, KEY_SEOL},
993941Svenki	{TICODE_kEXT, KEY_SEXIT},
1005029Sfw157321	{TICODE_kfnd, KEY_FIND},
1015029Sfw157321	{TICODE_kbeg, KEY_BEG},
1023941Svenki	{TICODE_kcan, KEY_CANCEL},
1033941Svenki	{TICODE_kclo, KEY_CLOSE},
1047746SKelly.Moyer@Sun.COM	{TICODE_kcmd, KEY_COMMAND},
1057746SKelly.Moyer@Sun.COM	{TICODE_kcpy, KEY_COPY},
1067746SKelly.Moyer@Sun.COM	{TICODE_kcrt, KEY_CREATE},
1077746SKelly.Moyer@Sun.COM	{TICODE_kend, KEY_END},
1087746SKelly.Moyer@Sun.COM	{TICODE_kent, KEY_ENTER},
1097746SKelly.Moyer@Sun.COM	{TICODE_kext, KEY_EXIT},
1107746SKelly.Moyer@Sun.COM	{TICODE_kf11, KEY_F(11)},
1117746SKelly.Moyer@Sun.COM	{TICODE_kf12, KEY_F(12)},
1127746SKelly.Moyer@Sun.COM	{TICODE_kf13, KEY_F(13)},
1137746SKelly.Moyer@Sun.COM	{TICODE_kf14, KEY_F(14)},
1147746SKelly.Moyer@Sun.COM	{TICODE_kf15, KEY_F(15)},
1157746SKelly.Moyer@Sun.COM	{TICODE_kf16, KEY_F(16)},
1167746SKelly.Moyer@Sun.COM	{TICODE_kf17, KEY_F(17)},
1177746SKelly.Moyer@Sun.COM	{TICODE_kf18, KEY_F(18)},
1187746SKelly.Moyer@Sun.COM	{TICODE_kf19, KEY_F(19)},
1197746SKelly.Moyer@Sun.COM	{TICODE_kf20, KEY_F(20)},
1207746SKelly.Moyer@Sun.COM	{TICODE_kf21, KEY_F(21)},
1217746SKelly.Moyer@Sun.COM	{TICODE_kf22, KEY_F(22)},
1227746SKelly.Moyer@Sun.COM	{TICODE_kf23, KEY_F(23)},
1237746SKelly.Moyer@Sun.COM	{TICODE_kf24, KEY_F(24)},
1247746SKelly.Moyer@Sun.COM	{TICODE_kf25, KEY_F(25)},
1257746SKelly.Moyer@Sun.COM	{TICODE_kf26, KEY_F(26)},
1267746SKelly.Moyer@Sun.COM	{TICODE_kf27, KEY_F(27)},
1277746SKelly.Moyer@Sun.COM	{TICODE_kf28, KEY_F(28)},
1283941Svenki	{TICODE_kf29, KEY_F(29)},
1293941Svenki	{TICODE_kf30, KEY_F(30)},
1303941Svenki	{TICODE_kf31, KEY_F(31)},
1313941Svenki	{TICODE_kf32, KEY_F(32)},
1323941Svenki	{TICODE_kf33, KEY_F(33)},
1333941Svenki	{TICODE_kf34, KEY_F(34)},
1343941Svenki	{TICODE_kf35, KEY_F(35)},
1353941Svenki	{TICODE_kf36, KEY_F(36)},
1363941Svenki	{TICODE_kf37, KEY_F(37)},
1373941Svenki	{TICODE_kf38, KEY_F(38)},
1383941Svenki	{TICODE_kf39, KEY_F(39)},
1393941Svenki	{TICODE_kf40, KEY_F(40)},
1403941Svenki	{TICODE_kf41, KEY_F(41)},
1413941Svenki	{TICODE_kf42, KEY_F(42)},
1423941Svenki	{TICODE_kf43, KEY_F(43)},
1433941Svenki	{TICODE_kf44, KEY_F(44)},
1443941Svenki	{TICODE_kf45, KEY_F(45)},
1453941Svenki	{TICODE_kf46, KEY_F(46)},
1463941Svenki	{TICODE_kf47, KEY_F(47)},
1473941Svenki	{TICODE_kf48, KEY_F(48)},
1483941Svenki	{TICODE_kf49, KEY_F(49)},
1493941Svenki	{TICODE_kf50, KEY_F(50)},
1503941Svenki	{TICODE_kf51, KEY_F(51)},
1513941Svenki	{TICODE_kf52, KEY_F(52)},
1523941Svenki	{TICODE_kf53, KEY_F(53)},
1533941Svenki	{TICODE_kf54, KEY_F(54)},
1543941Svenki	{TICODE_kf55, KEY_F(55)},
1553941Svenki	{TICODE_kf56, KEY_F(56)},
1563941Svenki	{TICODE_kf57, KEY_F(57)},
1573941Svenki	{TICODE_kf58, KEY_F(58)},
1583941Svenki	{TICODE_kf59, KEY_F(59)},
1595723Sfw157321	{TICODE_kf60, KEY_F(60)},
1605723Sfw157321	{TICODE_kf61, KEY_F(61)},
1615723Sfw157321	{TICODE_kf62, KEY_F(62)},
1625723Sfw157321	{TICODE_kf63, KEY_F(63)},
1635723Sfw157321	{TICODE_ka1, KEY_A1},
1645723Sfw157321	{TICODE_kb2, KEY_B2},
1655723Sfw157321	{TICODE_ka3, KEY_A3},
1665723Sfw157321	{TICODE_kc1, KEY_C1},
1675723Sfw157321	{TICODE_kc3, KEY_C3},
1685723Sfw157321	{TICODE_kmous, KEY_MOUSE},
1698411SKelly.Moyer@Sun.COM	{TICODE_kf0, KEY_F0},
1705723Sfw157321	{TICODE_kf1, KEY_F(1)},
1715723Sfw157321	{TICODE_kf2, KEY_F(2)},
1723941Svenki	{TICODE_kf3, KEY_F(3)},
1733941Svenki	{TICODE_kf4, KEY_F(4)},
1743941Svenki	{TICODE_kf5, KEY_F(5)},
1753941Svenki	{TICODE_kf6, KEY_F(6)},
1763941Svenki	{TICODE_kf7, KEY_F(7)},
1773941Svenki	{TICODE_kf8, KEY_F(8)},
1783941Svenki	{TICODE_kf9, KEY_F(9)},
1793941Svenki	{TICODE_kf10, KEY_F(10)},
1803941Svenki	{TICODE_kil1, KEY_IL},
1813941Svenki	{TICODE_ktbc, KEY_CATAB},
1823941Svenki	{TICODE_kcbt, KEY_BTAB},
1833941Svenki	{TICODE_kbs, KEY_BACKSPACE},
1843941Svenki	{TICODE_kclr, KEY_CLEAR},
1853941Svenki	{TICODE_kdch1, KEY_DC},
1863941Svenki	{TICODE_kcud1, KEY_DOWN},
1873941Svenki	{TICODE_kel, KEY_EOL},
1883941Svenki	{TICODE_kind, KEY_SF},
1893941Svenki	{TICODE_kll, KEY_LL},
1905723Sfw157321	{TICODE_khome, KEY_HOME},
1915723Sfw157321	{TICODE_kich1, KEY_IC},
1925723Sfw157321	{TICODE_kdl1, KEY_DL},
1935723Sfw157321	{TICODE_kcub1, KEY_LEFT},
1945723Sfw157321	{TICODE_krmir, KEY_EIC},
1955723Sfw157321	{TICODE_knp, KEY_NPAGE},
1965723Sfw157321	{TICODE_kpp, KEY_PPAGE},
1975723Sfw157321	{TICODE_kri, KEY_SR},
1985723Sfw157321	{TICODE_kcuf1, KEY_RIGHT},
1995723Sfw157321	{TICODE_ked, KEY_EOS},
2005723Sfw157321	{TICODE_khts, KEY_STAB},
2015723Sfw157321	{TICODE_kctab, KEY_CTAB},
2025723Sfw157321	{TICODE_kcuu1, KEY_UP}
2035723Sfw157321};
2045723Sfw157321/* Number of TC entries .... */
2053941Svenkistatic const int num_tcs = (sizeof(tc) / sizeof(struct tcdata));
2063941Svenki
2073941Svenki/* Key buffer */
2083941Svenki#define INBUF_SZ 16		/* size of key buffer - must be larger than
2093941Svenki				 * longest multi-key sequence */
2103941Svenkistatic wchar_t	inbuf[INBUF_SZ];
2113941Svenkistatic int	start, end, working; /* pointers for manipulating inbuf data */
2123941Svenki
2133941Svenki/* prototypes for private functions */
2143941Svenkistatic void add_key_sequence(SCREEN *screen, const char *sequence, int key_type);
2153941Svenkistatic key_entry_t *add_new_key(keymap_t *current, char ch, int key_type,
2163941Svenki        int symbol);
2173941Svenkistatic void delete_key_sequence(keymap_t *current, int key_type);
2183941Svenkistatic void do_keyok(keymap_t *current, int key_type, bool set, bool flag,
2193941Svenki	int *retval);
2203941Svenkistatic keymap_t *new_keymap(void); /* create a new keymap */
2213941Svenkistatic key_entry_t *new_key(void); /* create a new key entry */
2223941Svenkistatic wchar_t		inkey(int to, int delay);
2233941Svenki
2243941Svenki/*
2253941Svenki * Free the storage associated with the given keymap
2263941Svenki */
2273941Svenkivoid
2283941Svenki_cursesi_free_keymap(keymap_t *map)
2293941Svenki{
2303941Svenki	int i;
2313941Svenki
2323941Svenki	  /* check for, and free, child keymaps */
2333941Svenki	for (i = 0; i < MAX_CHAR; i++) {
2343941Svenki		if (map->mapping[i] >= 0) {
2353941Svenki			if (map->key[map->mapping[i]]->type == KEYMAP_MULTI)
2363941Svenki				_cursesi_free_keymap(
2373941Svenki					map->key[map->mapping[i]]->value.next);
2383941Svenki		}
2393941Svenki	}
2403941Svenki
2413941Svenki	  /* now free any allocated keymap structs */
2423941Svenki	for (i = 0; i < map->count; i += KEYMAP_ALLOC_CHUNK) {
2433941Svenki		free(map->key[i]);
2443941Svenki	}
2453941Svenki
2463941Svenki	free(map->key);
2473941Svenki	free(map);
2483941Svenki}
2493941Svenki
2503941Svenki
2513941Svenki/*
2523941Svenki * Add a new key entry to the keymap pointed to by current.  Entry
2533941Svenki * contains the character to add to the keymap, type is the type of
2543941Svenki * entry to add (either multikey or leaf) and symbol is the symbolic
2555723Sfw157321 * value for a leaf type entry.  The function returns a pointer to the
2563941Svenki * new keymap entry.
2573941Svenki */
2583941Svenkistatic key_entry_t *
2593941Svenkiadd_new_key(keymap_t *current, char chr, int key_type, int symbol)
2603941Svenki{
2613941Svenki	key_entry_t *the_key;
2623941Svenki        int i, ki;
2633941Svenki
2643941Svenki	__CTRACE(__CTRACE_MISC,
2653941Svenki	    "Adding character %s of type %d, symbol 0x%x\n",
2663941Svenki	    unctrl(chr), key_type, symbol);
2673941Svenki	if (current->mapping[(unsigned char)chr] < 0) {
2683941Svenki		if (current->mapping[(unsigned char)chr] == MAPPING_UNUSED) {
2693941Svenki			  /* first time for this char */
2703941Svenki			current->mapping[(unsigned char)chr] =
2717746SKelly.Moyer@Sun.COM				current->count;	/* map new entry */
2727746SKelly.Moyer@Sun.COM			ki = current->count;
2737746SKelly.Moyer@Sun.COM
2743941Svenki			  /* make sure we have room in the key array first */
2753941Svenki			if ((current->count & (KEYMAP_ALLOC_CHUNK - 1)) == 0)
2763941Svenki			{
2773941Svenki				if ((current->key =
2783941Svenki				     realloc(current->key,
2793941Svenki					     ki * sizeof(key_entry_t *)
2803941Svenki					     + KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t *))) == NULL) {
2813941Svenki					fprintf(stderr,
2823941Svenki					  "Could not malloc for key entry\n");
2833941Svenki					exit(1);
2843941Svenki				}
2853941Svenki
2863941Svenki				the_key = new_key();
2873941Svenki				for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) {
2883941Svenki					current->key[ki + i] = &the_key[i];
2893941Svenki				}
2903941Svenki			}
2913941Svenki                } else {
2923941Svenki			  /* the mapping was used but freed, reuse it */
2933941Svenki			ki = - current->mapping[(unsigned char) chr];
2943941Svenki			current->mapping[(unsigned char) chr] = ki;
2953941Svenki		}
2963941Svenki
2973941Svenki		current->count++;
2983941Svenki
2993941Svenki		  /* point at the current key array element to use */
3003941Svenki		the_key = current->key[ki];
3013941Svenki
3023941Svenki		the_key->type = key_type;
3033941Svenki
3043941Svenki		switch (key_type) {
3053941Svenki		case KEYMAP_MULTI:
3063941Svenki			/* need for next key */
3073941Svenki			__CTRACE(__CTRACE_MISC, "Creating new keymap\n");
3083941Svenki			the_key->value.next = new_keymap();
3093941Svenki			the_key->enable = TRUE;
3103941Svenki			break;
3113941Svenki
3123941Svenki		case KEYMAP_LEAF:
3133941Svenki			/* the associated symbol for the key */
3143941Svenki			__CTRACE(__CTRACE_MISC, "Adding leaf key\n");
3153941Svenki			the_key->value.symbol = symbol;
3167382SMichael.Bergknoff@Sun.COM			the_key->enable = TRUE;
3173941Svenki			break;
3183941Svenki
3193941Svenki		default:
3203941Svenki			fprintf(stderr, "add_new_key: bad type passed\n");
3213941Svenki			exit(1);
3223941Svenki		}
3233941Svenki	} else {
3243941Svenki		/* the key is already known - just return the address. */
3253941Svenki		__CTRACE(__CTRACE_MISC, "Keymap already known\n");
3263941Svenki		the_key = current->key[current->mapping[(unsigned char)chr]];
3275029Sfw157321	}
3285029Sfw157321
3293941Svenki        return the_key;
3303941Svenki}
3313941Svenki
3323941Svenki/*
3333941Svenki * Delete the given key symbol from the key mappings for the screen.
3343941Svenki *
3353941Svenki */
3365029Sfw157321static void
3373941Svenkidelete_key_sequence(keymap_t *current, int key_type)
3383941Svenki{
3395029Sfw157321	key_entry_t *key;
3405029Sfw157321	int i;
3415029Sfw157321
3425029Sfw157321	  /*
3435029Sfw157321	   * we need to iterate over all the keys as there may be
3447746SKelly.Moyer@Sun.COM	   * multiple instances of the leaf symbol.
3457746SKelly.Moyer@Sun.COM	   */
3467746SKelly.Moyer@Sun.COM	for (i = 0; i < MAX_CHAR; i++) {
3477746SKelly.Moyer@Sun.COM		if (current->mapping[i] < 0)
3487746SKelly.Moyer@Sun.COM			continue; /* no mapping for the key, next! */
3497746SKelly.Moyer@Sun.COM
3507746SKelly.Moyer@Sun.COM		key = current->key[current->mapping[i]];
3517746SKelly.Moyer@Sun.COM
3527746SKelly.Moyer@Sun.COM		if (key->type == KEYMAP_MULTI) {
3537746SKelly.Moyer@Sun.COM			  /* have not found the leaf, recurse down */
3547746SKelly.Moyer@Sun.COM			delete_key_sequence(key->value.next, key_type);
3557746SKelly.Moyer@Sun.COM			  /* if we deleted the last key in the map, free */
3567746SKelly.Moyer@Sun.COM			if (key->value.next->count == 0)
3577746SKelly.Moyer@Sun.COM				_cursesi_free_keymap(key->value.next);
3587746SKelly.Moyer@Sun.COM		} else if ((key->type == KEYMAP_LEAF)
3597746SKelly.Moyer@Sun.COM			   && (key->value.symbol == key_type)) {
3607746SKelly.Moyer@Sun.COM		__CTRACE(__CTRACE_INPUT,
3617746SKelly.Moyer@Sun.COM		    "delete_key_sequence: found keysym %d, deleting\n",
3627746SKelly.Moyer@Sun.COM		    key_type);
3637746SKelly.Moyer@Sun.COM			key->enable = FALSE;
3643941Svenki		}
3653941Svenki	}
3663941Svenki}
3673941Svenki
3683941Svenki/*
3693941Svenki * Add the sequence of characters given in sequence as the key mapping
3705029Sfw157321 * for the given key symbol.
3715029Sfw157321 */
3725029Sfw157321static void
3733941Svenkiadd_key_sequence(SCREEN *screen, const char *sequence, int key_type)
3745029Sfw157321{
3755029Sfw157321	key_entry_t *tmp_key;
3765029Sfw157321	keymap_t *current;
3775029Sfw157321	int length, j, key_ent;
3785029Sfw157321
3795029Sfw157321	__CTRACE(__CTRACE_MISC, "add_key_sequence: add key sequence: %s(%s)\n",
3805029Sfw157321	    sequence, keyname(key_type));
3815029Sfw157321	current = screen->base_keymap;	/* always start with
3825029Sfw157321					 * base keymap. */
3835029Sfw157321	length = (int)strlen(sequence);
3845029Sfw157321
3855029Sfw157321	/*
3865029Sfw157321	 * OK - we really should never get a zero length string here, either
3875029Sfw157321	 * the terminfo entry is there and it has a value or we are not called
3885029Sfw157321	 * at all.  Unfortunately, if someone assigns a terminfo string to the
3895029Sfw157321	 * ^@ value we get passed a null string which messes up our length.
3907746SKelly.Moyer@Sun.COM	 * So, if we get a null string then just insert a leaf value in
3917746SKelly.Moyer@Sun.COM	 * the 0th char position of the root keymap.  Note that we are
3927746SKelly.Moyer@Sun.COM	 * totally screwed if someone terminates a multichar sequence
3935029Sfw157321	 * with ^@... oh well.
3945029Sfw157321	 */
3955029Sfw157321	if (length == 0)
3965029Sfw157321		length = 1;
3975436Sfw157321
3985029Sfw157321	for (j = 0; j < length - 1; j++) {
3995029Sfw157321		  /* add the entry to the struct */
40011471SMichael.Bergknoff@Sun.COM		tmp_key = add_new_key(current, sequence[j], KEYMAP_MULTI, 0);
40111471SMichael.Bergknoff@Sun.COM
40211471SMichael.Bergknoff@Sun.COM		  /* index into the key array - it's
4035029Sfw157321		     clearer if we stash this */
4045029Sfw157321		key_ent = current->mapping[(unsigned char) sequence[j]];
4055029Sfw157321
4065029Sfw157321		current->key[key_ent] = tmp_key;
4075029Sfw157321
4085029Sfw157321		  /* next key uses this map... */
4095029Sfw157321		current = current->key[key_ent]->value.next;
4105029Sfw157321	}
4115029Sfw157321
4125029Sfw157321	/*
4133941Svenki	 * This is the last key in the sequence (it may have been the
4143941Svenki	 * only one but that does not matter) this means it is a leaf
4153941Svenki	 * key and should have a symbol associated with it.
4163941Svenki	 */
4173941Svenki	tmp_key = add_new_key(current, sequence[length - 1], KEYMAP_LEAF,
4183941Svenki			      key_type);
41911471SMichael.Bergknoff@Sun.COM	current->key[current->mapping[(int)sequence[length - 1]]] = tmp_key;
42011471SMichael.Bergknoff@Sun.COM}
42111471SMichael.Bergknoff@Sun.COM
42211471SMichael.Bergknoff@Sun.COM/*
42311471SMichael.Bergknoff@Sun.COM * Init_getch - initialise all the pointers & structures needed to make
42411471SMichael.Bergknoff@Sun.COM * getch work in keypad mode.
42511471SMichael.Bergknoff@Sun.COM *
42611471SMichael.Bergknoff@Sun.COM */
42711471SMichael.Bergknoff@Sun.COMvoid
42811471SMichael.Bergknoff@Sun.COM__init_getch(SCREEN *screen)
42911471SMichael.Bergknoff@Sun.COM{
43011471SMichael.Bergknoff@Sun.COM	char entry[1024], *p;
43111471SMichael.Bergknoff@Sun.COM	const char *s;
43211471SMichael.Bergknoff@Sun.COM	int     i;
4333941Svenki	size_t limit, l;
4343941Svenki#ifdef DEBUG
4353941Svenki	int k, length;
4363941Svenki#endif
4373941Svenki
4383941Svenki	/* init the inkey state variable */
4393941Svenki	_cursesi_state = INKEY_NORM;
44011471SMichael.Bergknoff@Sun.COM
44111471SMichael.Bergknoff@Sun.COM	/* init the base keymap */
44211471SMichael.Bergknoff@Sun.COM	screen->base_keymap = new_keymap();
44311471SMichael.Bergknoff@Sun.COM
44411471SMichael.Bergknoff@Sun.COM	/* key input buffer pointers */
44511471SMichael.Bergknoff@Sun.COM	start = end = working = 0;
44611471SMichael.Bergknoff@Sun.COM
44711471SMichael.Bergknoff@Sun.COM	/* now do the terminfo snarfing ... */
44811471SMichael.Bergknoff@Sun.COM
44911471SMichael.Bergknoff@Sun.COM	for (i = 0; i < num_tcs; i++) {
45011471SMichael.Bergknoff@Sun.COM		p = entry;
45111471SMichael.Bergknoff@Sun.COM		limit = 1023;
45211471SMichael.Bergknoff@Sun.COM		s = screen->term->strs[tc[i].code];
4533941Svenki		if (s == NULL)
4543941Svenki			continue;
4553941Svenki		l = strlen(s) + 1;
4563941Svenki		if (limit < l)
4573941Svenki			continue;
4583941Svenki		strlcpy(p, s, limit);
4593941Svenki		p += l;
4603941Svenki		limit -= l;
4613941Svenki#ifdef DEBUG
4623941Svenki			__CTRACE(__CTRACE_INIT,
4633941Svenki			    "Processing terminfo entry %d, sequence ",
4643941Svenki			    tc[i].code);
4653941Svenki			length = (int) strlen(entry);
4663941Svenki			for (k = 0; k <= length -1; k++)
4673941Svenki				__CTRACE(__CTRACE_INIT, "%s", unctrl(entry[k]));
4683941Svenki			__CTRACE(__CTRACE_INIT, "\n");
4695723Sfw157321#endif
4705723Sfw157321		add_key_sequence(screen, entry, tc[i].symbol);
4713941Svenki	}
4723941Svenki}
4735723Sfw157321
4745723Sfw157321
4755723Sfw157321/*
4763941Svenki * new_keymap - allocates & initialises a new keymap structure.  This
4773941Svenki * function returns a pointer to the new keymap.
4783941Svenki *
4793941Svenki */
4803941Svenkistatic keymap_t *
4813941Svenkinew_keymap(void)
4823941Svenki{
4833941Svenki	int     i;
4843941Svenki	keymap_t *new_map;
4853941Svenki
4865029Sfw157321	if ((new_map = malloc(sizeof(keymap_t))) == NULL) {
4875029Sfw157321		perror("Inkey: Cannot allocate new keymap");
4885029Sfw157321		exit(2);
4895029Sfw157321	}
4905029Sfw157321
4915029Sfw157321	/* Initialise the new map */
4923941Svenki	new_map->count = 0;
4933941Svenki	for (i = 0; i < MAX_CHAR; i++) {
4943941Svenki		new_map->mapping[i] = MAPPING_UNUSED; /* no mapping for char */
4953941Svenki	}
4963941Svenki
4975029Sfw157321	/* key array will be allocated when first key is added */
4983941Svenki	new_map->key = NULL;
4993941Svenki
5003941Svenki	return new_map;
5013941Svenki}
5023941Svenki
5033941Svenki/*
5043941Svenki * new_key - allocates & initialises a new key entry.  This function returns
5053941Svenki * a pointer to the newly allocated key entry.
5063941Svenki *
5073941Svenki */
5083941Svenkistatic key_entry_t *
5095029Sfw157321new_key(void)
5103941Svenki{
5117746SKelly.Moyer@Sun.COM	key_entry_t *new_one;
5123941Svenki	int i;
5135029Sfw157321
5143941Svenki	new_one = malloc(KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t));
5153941Svenki	if (new_one == NULL) {
5163941Svenki		perror("inkey: Cannot allocate new key entry chunk");
5173941Svenki		exit(2);
5183941Svenki	}
5193941Svenki
5203941Svenki	for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) {
5213941Svenki		new_one[i].type = 0;
5223941Svenki		new_one[i].value.next = NULL;
5233941Svenki	}
5243941Svenki
5255029Sfw157321	return new_one;
5263941Svenki}
5273941Svenki
5287746SKelly.Moyer@Sun.COM/*
5293941Svenki * inkey - do the work to process keyboard input, check for multi-key
5305029Sfw157321 * sequences and return the appropriate symbol if we get a match.
5313941Svenki *
5323941Svenki */
5333941Svenki
5343941Svenkistatic wchar_t
5353941Svenkiinkey(int to, int delay)
5363941Svenki{
5373941Svenki	wchar_t		 k;
5383941Svenki	int              c, mapping;
5393941Svenki	keymap_t	*current = _cursesi_screen->base_keymap;
5403941Svenki	FILE            *infd = _cursesi_screen->infd;
5413941Svenki
5423941Svenki	k = 0;		/* XXX gcc -Wuninitialized */
5433941Svenki
5443941Svenki	__CTRACE(__CTRACE_INPUT, "inkey (%d, %d)\n", to, delay);
5453941Svenki	for (;;) {		/* loop until we get a complete key sequence */
5463941Svenkireread:
5473941Svenki		if (_cursesi_state == INKEY_NORM) {
5483941Svenki			if (delay && __timeout(delay) == ERR)
5493941Svenki				return ERR;
5503941Svenki			c = __fgetc_resize(infd);
5513941Svenki			if (c == ERR || c == KEY_RESIZE) {
5523941Svenki				clearerr(infd);
5533941Svenki				return c;
5543941Svenki			}
5553941Svenki
5563941Svenki			if (delay && (__notimeout() == ERR))
5573941Svenki				return ERR;
5583941Svenki
5593941Svenki			k = (wchar_t)c;
5603941Svenki			__CTRACE(__CTRACE_INPUT,
5613941Svenki			    "inkey (state normal) got '%s'\n", unctrl(k));
5623941Svenki
5633941Svenki			working = start;
5643941Svenki			inbuf[working] = k;
5653941Svenki			INC_POINTER(working);
5663941Svenki			end = working;
5676751Sfw157321
5683941Svenki			/* go to the assembling state now */
5693941Svenki			_cursesi_state = INKEY_ASSEMBLING;
5705723Sfw157321
5715723Sfw157321		} else if (_cursesi_state == INKEY_BACKOUT) {
5725723Sfw157321			k = inbuf[working];
5733941Svenki			INC_POINTER(working);
5743941Svenki			if (working == end) {	/* see if we have run
5753941Svenki						 * out of keys in the
5763941Svenki						 * backlog */
5773941Svenki
5783941Svenki				/* if we have then switch to assembling */
5793941Svenki				_cursesi_state = INKEY_ASSEMBLING;
5803941Svenki			}
5813941Svenki		} else if (_cursesi_state == INKEY_ASSEMBLING) {
5823941Svenki			/* assembling a key sequence */
5833941Svenki			if (delay) {
5843941Svenki				if (__timeout(to ? (ESCDELAY / 100) : delay)
5853941Svenki				    == ERR)
5863941Svenki					return ERR;
5873941Svenki			} else {
5883941Svenki				if (to && (__timeout(ESCDELAY / 100) == ERR))
5893941Svenki					return ERR;
5905995Sfw157321			}
5913941Svenki
5925995Sfw157321			c = __fgetc_resize(infd);
5935995Sfw157321			if (ferror(infd)) {
5943941Svenki				clearerr(infd);
5953941Svenki				return c;
5963941Svenki			}
5973941Svenki
5983941Svenki			if ((to || delay) && (__notimeout() == ERR))
5993941Svenki					return ERR;
6003941Svenki
6013941Svenki			__CTRACE(__CTRACE_INPUT,
6023941Svenki			    "inkey (state assembling) got '%s'\n", unctrl(k));
6035995Sfw157321			if (feof(infd) || c == -1) {	/* inter-char timeout,
6045995Sfw157321							 * start backing out */
6055995Sfw157321				clearerr(infd);
6065995Sfw157321				if (start == end)
6075995Sfw157321					/* no chars in the buffer, restart */
6085995Sfw157321					goto reread;
6095995Sfw157321
6105995Sfw157321				k = inbuf[start];
6115995Sfw157321				_cursesi_state = INKEY_TIMEOUT;
6125995Sfw157321			} else {
6135995Sfw157321				k = (wchar_t) c;
6145995Sfw157321				inbuf[working] = k;
6155995Sfw157321				INC_POINTER(working);
6165995Sfw157321				end = working;
6175995Sfw157321			}
6185995Sfw157321		} else {
6195995Sfw157321			fprintf(stderr, "Inkey state screwed - exiting!!!");
6205995Sfw157321			exit(2);
6215995Sfw157321		}
6223941Svenki
6233941Svenki		  /*
6243941Svenki		   * Check key has no special meaning and we have not
6253941Svenki		   * timed out and the key has not been disabled
6263941Svenki		   */
6273941Svenki		mapping = current->mapping[k];
6283941Svenki		if (((_cursesi_state == INKEY_TIMEOUT) || (mapping < 0))
6293941Svenki			|| ((current->key[mapping]->type == KEYMAP_LEAF)
6303941Svenki			    && (current->key[mapping]->enable == FALSE))) {
6313941Svenki			/* return the first key we know about */
6323941Svenki			k = inbuf[start];
6333941Svenki
6343941Svenki			INC_POINTER(start);
6353941Svenki			working = start;
6363941Svenki
6375723Sfw157321			if (start == end) {	/* only one char processed */
6385723Sfw157321				_cursesi_state = INKEY_NORM;
6395723Sfw157321			} else {/* otherwise we must have more than one char
6403941Svenki				 * to backout */
6413941Svenki				_cursesi_state = INKEY_BACKOUT;
6423941Svenki			}
6433941Svenki			return k;
6443941Svenki		} else {	/* must be part of a multikey sequence */
6453941Svenki			/* check for completed key sequence */
6463941Svenki			if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) {
6473941Svenki				start = working;	/* eat the key sequence
6483941Svenki							 * in inbuf */
6493941Svenki
6503941Svenki				/* check if inbuf empty now */
6513941Svenki				if (start == end) {
6523941Svenki					/* if it is go back to normal */
6533941Svenki					_cursesi_state = INKEY_NORM;
6543941Svenki				} else {
6553941Svenki					/* otherwise go to backout state */
6563941Svenki					_cursesi_state = INKEY_BACKOUT;
6573941Svenki				}
6583941Svenki
6593941Svenki				/* return the symbol */
6603941Svenki				return current->key[current->mapping[k]]->value.symbol;
6613941Svenki
6623941Svenki			} else {
6633941Svenki				/*
6643941Svenki				 * Step on to next part of the multi-key
6653941Svenki				 * sequence.
6663941Svenki				 */
6673941Svenki				current = current->key[current->mapping[k]]->value.next;
6683941Svenki			}
6693941Svenki		}
6703941Svenki	}
6713941Svenki}
6723941Svenki
6733941Svenki#ifndef _CURSES_USE_MACROS
6743941Svenki/*
6753941Svenki * getch --
6763941Svenki *	Read in a character from stdscr.
6773941Svenki */
6783941Svenkiint
6793941Svenkigetch(void)
6803941Svenki{
6813941Svenki	return wgetch(stdscr);
6823941Svenki}
6833941Svenki
6843941Svenki/*
6853941Svenki * mvgetch --
68610406SMichael.Bergknoff@Sun.COM *      Read in a character from stdscr at the given location.
6873941Svenki */
6883941Svenkiint
6893941Svenkimvgetch(int y, int x)
6903941Svenki{
6913941Svenki	return mvwgetch(stdscr, y, x);
6923941Svenki}
6933941Svenki
6943941Svenki/*
6953941Svenki * mvwgetch --
6963941Svenki *      Read in a character from stdscr at the given location in the
6973941Svenki *      given window.
6983941Svenki */
6993941Svenkiint
7003941Svenkimvwgetch(WINDOW *win, int y, int x)
7013941Svenki{
7023941Svenki	if (wmove(win, y, x) == ERR)
7033941Svenki		return ERR;
7043941Svenki
7053941Svenki	return wgetch(win);
7063941Svenki}
7073941Svenki
7083941Svenki#endif
7093941Svenki
7103941Svenki/*
7113941Svenki * keyok --
7123941Svenki *      Set the enable flag for a keysym, if the flag is false then
7133941Svenki * getch will not return this keysym even if the matching key sequence
7143941Svenki * is seen.
7153941Svenki */
7163941Svenkiint
7173941Svenkikeyok(int key_type, bool flag)
7183941Svenki{
7193941Svenki	int result = ERR;
7203941Svenki
7213941Svenki	if (_cursesi_screen != NULL)
7223941Svenki		do_keyok(_cursesi_screen->base_keymap, key_type,
7233941Svenki		    true, flag, &result);
7243941Svenki	return result;
7253941Svenki}
7263941Svenki
7273941Svenki/*
7283941Svenki * do_keyok --
7293941Svenki *       Does the actual work for keyok, we need to recurse through the
7303941Svenki * keymaps finding the passed key symbol.
7313941Svenki */
7323941Svenkistatic void
7333941Svenkido_keyok(keymap_t *current, int key_type, bool set, bool flag, int *retval)
7343941Svenki{
7353941Svenki	key_entry_t *key;
7363941Svenki	int i;
7373941Svenki
7383941Svenki	  /*
7393941Svenki	   * we need to iterate over all the keys as there may be
7403941Svenki	   * multiple instances of the leaf symbol.
7413941Svenki	   */
7423941Svenki	for (i = 0; i < MAX_CHAR; i++) {
7433941Svenki		if (current->mapping[i] < 0)
7443941Svenki			continue; /* no mapping for the key, next! */
7453941Svenki
7463941Svenki		key = current->key[current->mapping[i]];
7475723Sfw157321
7485723Sfw157321		if (key->type == KEYMAP_MULTI)
7495723Sfw157321			do_keyok(key->value.next, key_type, set, flag, retval);
7503941Svenki		else if ((key->type == KEYMAP_LEAF)
7513941Svenki			 && (key->value.symbol == key_type)) {
7523941Svenki			if (set)
7533941Svenki				key->enable = flag;
7543941Svenki			*retval = OK; /* we found at least one instance, ok */
7553941Svenki		}
7563941Svenki	}
7573941Svenki}
7583941Svenki
7593941Svenki/*
7605723Sfw157321 * define_key --
7615723Sfw157321 *      Add a custom mapping of a key sequence to key symbol.
7625723Sfw157321 *
7633941Svenki */
7643941Svenkiint
7653941Svenkidefine_key(const char *sequence, int symbol)
7663941Svenki{
7673941Svenki
7683941Svenki	if (symbol <= 0 || _cursesi_screen == NULL)
7693941Svenki		return ERR;
7703941Svenki
7713941Svenki	if (sequence == NULL) {
7723941Svenki		__CTRACE(__CTRACE_INPUT, "define_key: deleting keysym %d\n",
7735723Sfw157321		    symbol);
7745723Sfw157321		delete_key_sequence(_cursesi_screen->base_keymap, symbol);
7755723Sfw157321	} else
7763941Svenki		add_key_sequence(_cursesi_screen, sequence, symbol);
7773941Svenki
7783941Svenki	return OK;
7793941Svenki}
7803941Svenki
7814802Sfw157321/*
7823941Svenki * wgetch --
7834802Sfw157321 *	Read in a character from the window.
7843941Svenki */
7853941Svenkiint
7863941Svenkiwgetch(WINDOW *win)
7873941Svenki{
7883941Svenki	int inp, weset;
7893941Svenki	int c;
7903941Svenki	FILE *infd = _cursesi_screen->infd;
7913941Svenki
7923941Svenki	__CTRACE(__CTRACE_INPUT, "wgetch: win(%p)\n", win);
7933941Svenki	if (win == NULL)
7943941Svenki		return ERR;
7953941Svenki	if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN)
7963941Svenki	    && win->curx == win->maxx - 1 && win->cury == win->maxy - 1
7973941Svenki	    && __echoit)
7983941Svenki		return ERR;
7993941Svenki
8003941Svenki	if (!(win->flags & __ISPAD)) {
8013941Svenki		if (is_wintouched(win))
8023941Svenki			wrefresh(win);
8033941Svenki		else if (__echoit && ((_cursesi_screen->curscr->cury != (win->begy + win->cury))
8043941Svenki		         || (_cursesi_screen->curscr->curx != (win->begx + win->curx)))) {
8053941Svenki			__CTRACE(__CTRACE_INPUT,
8063941Svenki			    "wgetch: curscr cury %d cury %d "
8073941Svenki			    "curscr curx %d curx %d\n",
8083941Svenki			    _cursesi_screen->curscr->cury,
8093941Svenki			    win->begy + win->cury,
8103941Svenki			    _cursesi_screen->curscr->curx,
8113941Svenki			    win->begx + win->curx);
8123941Svenki			/*
8133941Svenki			 * Just in case the window is not dirty but the
8143941Svenki			 * cursor was  moved, check and update the
8153941Svenki			 * cursor location.
8163941Svenki			 */
8173941Svenki			mvcur(_cursesi_screen->curscr->cury,
8183941Svenki			    _cursesi_screen->curscr->curx,
8193941Svenki		      	    win->cury + win->begy, win->curx + win->begx);
8203941Svenki			_cursesi_screen->curscr->cury =
8213941Svenki			    win->cury + win->begy;
8223941Svenki			_cursesi_screen->curscr->curx =
8233941Svenki			    win->curx + win->begx;
8243941Svenki		}
8253941Svenki	}
8263941Svenki
8273941Svenki	__CTRACE(__CTRACE_INPUT, "wgetch: __echoit = %d, "
8283941Svenki	    "__rawmode = %d, __nl = %d, flags = %#.4x, delay = %d\n",
8293941Svenki	    __echoit, __rawmode, _cursesi_screen->nl, win->flags, win->delay);
8303941Svenki	if (_cursesi_screen->resized) {
8313941Svenki		resizeterm(LINES, COLS);
8323941Svenki		_cursesi_screen->resized = 0;
8335723Sfw157321		__CTRACE(__CTRACE_INPUT, "wgetch returning KEY_RESIZE\n");
8345723Sfw157321		return KEY_RESIZE;
8355723Sfw157321	}
8363941Svenki	if (_cursesi_screen->unget_pos) {
8373941Svenki		__CTRACE(__CTRACE_INPUT, "wgetch returning char at %d\n",
8383941Svenki		    _cursesi_screen->unget_pos);
8393941Svenki		_cursesi_screen->unget_pos--;
8403941Svenki		c = _cursesi_screen->unget_list[_cursesi_screen->unget_pos];
8413941Svenki		if (__echoit)
8423941Svenki			waddch(win, (chtype) c);
8433941Svenki		return c;
8443941Svenki	}
8453941Svenki	if (__echoit && !__rawmode) {
8463941Svenki		cbreak();
8473941Svenki		weset = 1;
8483941Svenki	} else
8493941Svenki		weset = 0;
8503941Svenki
8513941Svenki	__save_termios();
8523941Svenki
8533941Svenki	if (win->flags & __KEYPAD) {
8543941Svenki		switch (win->delay) {
8553941Svenki		case -1:
8563941Svenki			inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0);
8573941Svenki			break;
8583941Svenki		case 0:
8593941Svenki			if (__nodelay() == ERR)
8603941Svenki				return ERR;
8613941Svenki			inp = inkey(0, 0);
8623941Svenki			break;
8633941Svenki		default:
8643941Svenki			inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay);
8655723Sfw157321			break;
8665723Sfw157321		}
8675723Sfw157321	} else {
8683941Svenki		switch (win->delay) {
8693941Svenki		case -1:
8703941Svenki			if (__delay() == ERR)
8713941Svenki				return ERR;
8723941Svenki			break;
8733941Svenki		case 0:
8743941Svenki			if (__nodelay() == ERR)
8753941Svenki				return ERR;
8765723Sfw157321			break;
8775723Sfw157321		default:
8785723Sfw157321			if (__timeout(win->delay) == ERR)
8793941Svenki				return ERR;
8803941Svenki			break;
8813941Svenki		}
8823941Svenki
8833941Svenki		inp = __fgetc_resize(infd);
8843941Svenki		if (inp == ERR || inp == KEY_RESIZE) {
8853941Svenki			clearerr(infd);
8863941Svenki			__restore_termios();
8873941Svenki			return inp;
8883941Svenki		}
8893941Svenki	}
8903941Svenki#ifdef DEBUG
8913941Svenki	if (inp > 255)
8923941Svenki		  /* we have a key symbol - treat it differently */
8933941Svenki		  /* XXXX perhaps __unctrl should be expanded to include
8943941Svenki		   * XXXX the keysyms in the table....
8953941Svenki		   */
8963941Svenki		__CTRACE(__CTRACE_INPUT, "wgetch assembled keysym 0x%x\n", inp);
8973941Svenki	else
8983941Svenki		__CTRACE(__CTRACE_INPUT, "wgetch got '%s'\n", unctrl(inp));
8993941Svenki#endif
9003941Svenki	if (win->delay > -1) {
9013941Svenki		if (__delay() == ERR)
9023941Svenki			return ERR;
9033941Svenki	}
9043941Svenki
9053941Svenki	__restore_termios();
9063941Svenki
9073941Svenki	if ((__echoit) && (inp < KEY_MIN))
9083941Svenki		waddch(win, (chtype) inp);
9093941Svenki
9103941Svenki	if (weset)
9113941Svenki		nocbreak();
9123941Svenki
9133941Svenki	if (_cursesi_screen->nl && inp == 13)
9143941Svenki		inp = 10;
9153941Svenki
9163941Svenki	return ((inp < 0) || (inp == ERR) ? ERR : inp);
9173941Svenki}
9183941Svenki
9193941Svenki/*
9203941Svenki * ungetch --
9213941Svenki *     Put the character back into the input queue.
9223941Svenki */
9233941Svenkiint
9243941Svenkiungetch(int c)
9253941Svenki{
9263941Svenki	return __unget((wint_t)c);
9273941Svenki}
9283941Svenki
9293941Svenki/*
9303941Svenki * __unget --
9313941Svenki *    Do the work for ungetch() and unget_wch();
9323941Svenki */
9333941Svenkiint
9343941Svenki__unget(wint_t c)
9353941Svenki{
9363941Svenki	wchar_t	*p;
9373941Svenki	int	len;
9383941Svenki
9393941Svenki	__CTRACE(__CTRACE_INPUT, "__unget(%x)\n", c);
9403941Svenki	if (_cursesi_screen == NULL)
9413941Svenki		return ERR;
9423941Svenki	if (_cursesi_screen->unget_pos >= _cursesi_screen->unget_len) {
9433941Svenki		len = _cursesi_screen->unget_len + 32;
9443941Svenki		if ((p = realloc(_cursesi_screen->unget_list,
9453941Svenki		    sizeof(wchar_t) * len)) == NULL) {
9463941Svenki			/* Can't realloc(), so just lose the oldest entry */
9473941Svenki			memmove(_cursesi_screen->unget_list,
9483941Svenki			    _cursesi_screen->unget_list + sizeof(wchar_t),
9493941Svenki			    _cursesi_screen->unget_len - 1);
9503941Svenki			_cursesi_screen->unget_list[_cursesi_screen->unget_len
9513941Svenki			    - 1] = c;
9523941Svenki			_cursesi_screen->unget_pos =
9533941Svenki			    _cursesi_screen->unget_len;
9543941Svenki			return OK;
9553941Svenki		} else {
9563941Svenki			_cursesi_screen->unget_pos =
9573941Svenki			    _cursesi_screen->unget_len;
9583941Svenki			_cursesi_screen->unget_len = len;
9593941Svenki			_cursesi_screen->unget_list = p;
9603941Svenki		}
9613941Svenki	}
9623941Svenki	_cursesi_screen->unget_list[_cursesi_screen->unget_pos] = c;
9633941Svenki	_cursesi_screen->unget_pos++;
9643941Svenki	return OK;
9653941Svenki}
9663941Svenki
9673941Svenkiint
9683941Svenkihas_key(int key_type)
9693941Svenki{
9703941Svenki	int result = ERR;
9713941Svenki
9723941Svenki	if (_cursesi_screen != NULL)
9733941Svenki		do_keyok(_cursesi_screen->base_keymap, key_type,
9743941Svenki		    false, false, &result);
9753941Svenki	return result;
9763941Svenki}
9773941Svenki
9783941Svenki/*
9793941Svenki * set_escdelay --
9803941Svenki *   Sets the escape delay for the current screen.
9813941Svenki */
9823941Svenkiint
9833941Svenkiset_escdelay(int escdelay)
9843941Svenki{
9853941Svenki
9863941Svenki	if (_cursesi_screen == NULL)
9873941Svenki		return ERR;
9883941Svenki	_cursesi_screen->ESCDELAY = escdelay;
9893941Svenki	ESCDELAY = escdelay;
9903941Svenki	return OK;
9913941Svenki}
9923941Svenki
9933941Svenki/*
9943941Svenki * __fgetc_resize --
9953941Svenki *    Any call to fgetc(3) should use this function instead
9963941Svenki *    and test for the return value of KEY_RESIZE as well as ERR.
9973941Svenki */
9983941Svenkiint
9993941Svenki__fgetc_resize(FILE *infd)
10003941Svenki{
10013941Svenki	int c;
10023941Svenki
10033941Svenki	c = fgetc(infd);
10043941Svenki	if (c != EOF)
10053941Svenki		return c;
10063941Svenki
10073941Svenki	if (!ferror(infd) || errno != EINTR || !_cursesi_screen->resized)
10083941Svenki		return ERR;
10093941Svenki	__CTRACE(__CTRACE_INPUT, "__fgetc_resize returning KEY_RESIZE\n");
10103941Svenki	resizeterm(LINES, COLS);
10113941Svenki	_cursesi_screen->resized = 0;
10123941Svenki	return KEY_RESIZE;
10133941Svenki}
10143941Svenki