10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*9694SScott.Rotondo@Sun.COM * Common Development and Distribution License (the "License").
6*9694SScott.Rotondo@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*9694SScott.Rotondo@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
310Sstevel@tonic-gate * The Regents of the University of California
320Sstevel@tonic-gate * All Rights Reserved
330Sstevel@tonic-gate *
340Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
350Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
360Sstevel@tonic-gate * contributors.
370Sstevel@tonic-gate */
380Sstevel@tonic-gate
390Sstevel@tonic-gate /*LINTLIBRARY*/
400Sstevel@tonic-gate
410Sstevel@tonic-gate #include "curses_inc.h"
420Sstevel@tonic-gate #include <signal.h>
430Sstevel@tonic-gate #include <unistd.h>
440Sstevel@tonic-gate #ifdef DEBUG
450Sstevel@tonic-gate #include <ctype.h>
460Sstevel@tonic-gate #endif /* DEBUG */
470Sstevel@tonic-gate
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate * Read a key typed from the terminal
500Sstevel@tonic-gate *
510Sstevel@tonic-gate * interpret: = 0 for single-char key only
520Sstevel@tonic-gate * = 1 for matching function key and macro patterns.
530Sstevel@tonic-gate * = 2 same as 1 but no time-out for funckey matching.
540Sstevel@tonic-gate */
550Sstevel@tonic-gate
560Sstevel@tonic-gate static int _getkey(int, chtype *);
570Sstevel@tonic-gate static int _fpk(void);
580Sstevel@tonic-gate static int _pk(void);
590Sstevel@tonic-gate
600Sstevel@tonic-gate chtype
tgetch(int interpret)610Sstevel@tonic-gate tgetch(int interpret)
620Sstevel@tonic-gate {
630Sstevel@tonic-gate int i = 0, j, collapse = 1;
640Sstevel@tonic-gate #define WAIT3 333
650Sstevel@tonic-gate chtype inp;
660Sstevel@tonic-gate chtype *inputQ = cur_term->_input_queue;
670Sstevel@tonic-gate char *chars_onQ = &(cur_term->_chars_on_queue);
680Sstevel@tonic-gate
690Sstevel@tonic-gate #ifdef SYSV
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate * Register the fact that getch is being used so
720Sstevel@tonic-gate * that typeahead checking can be done.
730Sstevel@tonic-gate * This code should GO AWAY when a poll() or FIONREAD can
740Sstevel@tonic-gate * be done on the file descriptor as then the check
750Sstevel@tonic-gate * will be non-destructive.
760Sstevel@tonic-gate */
770Sstevel@tonic-gate cur_term->fl_typeahdok = TRUE;
780Sstevel@tonic-gate #endif /* SYSV */
790Sstevel@tonic-gate
800Sstevel@tonic-gate /* ask for input */
810Sstevel@tonic-gate if (cur_term->_ungotten > 0) {
820Sstevel@tonic-gate cur_term->_ungotten--;
830Sstevel@tonic-gate /* decode an ungetch()'d character */
840Sstevel@tonic-gate inp = -inputQ[0];
850Sstevel@tonic-gate } else {
860Sstevel@tonic-gate /* Only read a character if there is no typeahead/peekahead. */
870Sstevel@tonic-gate if (*chars_onQ == 0) {
880Sstevel@tonic-gate /* (*chars_onQ)++; MR */
890Sstevel@tonic-gate #ifdef FIONREAD
900Sstevel@tonic-gate inp = _readchar();
910Sstevel@tonic-gate #else /* FIONREAD */
920Sstevel@tonic-gate inp = (chtype) _pk();
930Sstevel@tonic-gate if ((int)inp == ERR) {
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate * interpret is set to 0 so that down below we don't
960Sstevel@tonic-gate * drop into getkey since we already know there can't be
970Sstevel@tonic-gate * a key that starts with -1. Also, we don't want to
980Sstevel@tonic-gate * access funckeystarter[-1].
990Sstevel@tonic-gate */
1000Sstevel@tonic-gate interpret = FALSE;
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate #endif /* FIONREAD */
1030Sstevel@tonic-gate (*chars_onQ)++;
1040Sstevel@tonic-gate } else
1050Sstevel@tonic-gate inp = inputQ[0];
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate #ifdef DEBUG
1080Sstevel@tonic-gate if (outf)
1090Sstevel@tonic-gate fprintf(outf, "TGETCH read '%s'\n", unctrl(inp));
1100Sstevel@tonic-gate #endif /* DEBUG */
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate /* Check for arrow and function keys */
1130Sstevel@tonic-gate if (interpret && cur_term->funckeystarter[inp])
114*9694SScott.Rotondo@Sun.COM collapse = _getkey(interpret - 1, &inp);
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate /* Collapse the input queue to remove the escape */
1180Sstevel@tonic-gate /* sequence from the stack. */
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate j = *chars_onQ;
1210Sstevel@tonic-gate (*chars_onQ) -= collapse;
1220Sstevel@tonic-gate while (collapse < j)
1230Sstevel@tonic-gate inputQ[i++] = inputQ[collapse++];
1240Sstevel@tonic-gate return (inp);
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate #ifdef FIONREAD
1280Sstevel@tonic-gate static int
_readchar()1290Sstevel@tonic-gate _readchar()
1300Sstevel@tonic-gate {
1310Sstevel@tonic-gate int i;
1320Sstevel@tonic-gate unsigned char c;
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate if (cur_term->_delay == 0) {
1350Sstevel@tonic-gate int arg;
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate (void) ioctl(cur_term->_inputfd, FIONREAD, &arg);
1380Sstevel@tonic-gate #ifdef DEBUG
1390Sstevel@tonic-gate if (outf)
1400Sstevel@tonic-gate fprintf(outf, "FIONREAD returns %d\n", arg);
1410Sstevel@tonic-gate #endif /* DEBUG */
1420Sstevel@tonic-gate if (arg < 1)
1430Sstevel@tonic-gate return (-1);
1440Sstevel@tonic-gate } else
1450Sstevel@tonic-gate if (cur_term->_delay > 0) {
1460Sstevel@tonic-gate char c;
1470Sstevel@tonic-gate int infd;
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate infd = 1 << cur_term->_inputfd;
1500Sstevel@tonic-gate t.tv_sec = cur_term->_delay / 1000;
1510Sstevel@tonic-gate t.tv_usec = (cur_term->_delay % 1000) * 1000;
1520Sstevel@tonic-gate i = select(20, &infd, (int *)NULL, (int *)NULL, &t);
1530Sstevel@tonic-gate if (i < 0)
1540Sstevel@tonic-gate return (ERR);
1550Sstevel@tonic-gate i = read(cur_term->_inputfd, &c, 1);
1560Sstevel@tonic-gate } else
1570Sstevel@tonic-gate i = read(cur_term->_inputfd, &c, 1);
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate #ifdef DEBUG
1600Sstevel@tonic-gate if (outf)
1610Sstevel@tonic-gate fprintf(outf, "read from %d returns %d chars, first %o\n",
1620Sstevel@tonic-gate cur_term->_inputfd, i, c);
1630Sstevel@tonic-gate #endif /* DEBUG */
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate if (i > 0)
1660Sstevel@tonic-gate return (c);
1670Sstevel@tonic-gate else
1680Sstevel@tonic-gate return (ERR);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate #endif /* !FIONREAD */
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate #ifdef DEBUG
1730Sstevel@tonic-gate extern char *_asciify();
1740Sstevel@tonic-gate #endif /* DEBUG */
1750Sstevel@tonic-gate
176*9694SScott.Rotondo@Sun.COM static int get_xterm_mouse(int, int *);
177*9694SScott.Rotondo@Sun.COM static void _map_button(chtype *);
178*9694SScott.Rotondo@Sun.COM
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate * This algorithm is a "learning" algorithm. The premise is
1810Sstevel@tonic-gate * that keys used once are like to be used again and again.
1820Sstevel@tonic-gate * Since the time for a linear search of the table is so
1830Sstevel@tonic-gate * expensive, we move keys that are found up to the top of
1840Sstevel@tonic-gate * the list, making the access to a repeated key very fast and
1850Sstevel@tonic-gate * keys that have been used before close to the top.
1860Sstevel@tonic-gate */
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate static int
_getkey(int blockpeek,chtype * inp)1890Sstevel@tonic-gate _getkey(int blockpeek, chtype *inp)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate _KEY_MAP **kp = cur_term->_keys;
1920Sstevel@tonic-gate int key, num_keys = cur_term->_ksz;
1930Sstevel@tonic-gate int i;
1940Sstevel@tonic-gate chtype *inputQ = cur_term->_input_queue;
195*9694SScott.Rotondo@Sun.COM char *chars_onQ = &(cur_term->_chars_on_queue);
196*9694SScott.Rotondo@Sun.COM char flag = cur_term->funckeystarter[*inp];
1970Sstevel@tonic-gate int first, collapse = 1;
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate #ifdef DEBUG
2010Sstevel@tonic-gate if (outf)
2020Sstevel@tonic-gate fprintf(outf, "getkey(): looking in linear table, "
2030Sstevel@tonic-gate "inp=%d\n", *inp);
2040Sstevel@tonic-gate #endif /* DEBUG */
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate if (flag & _KEY)
2070Sstevel@tonic-gate key = 0;
2080Sstevel@tonic-gate else {
2090Sstevel@tonic-gate key = cur_term->_first_macro;
2100Sstevel@tonic-gate blockpeek = TRUE;
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate first = key;
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate for (; key < num_keys; key++) {
2150Sstevel@tonic-gate if (kp[key]->_sends[0] == *inp) {
2160Sstevel@tonic-gate for (i = 1; i < INP_QSIZE; i++) {
2170Sstevel@tonic-gate /* found it? */
2180Sstevel@tonic-gate if (kp[key]->_sends[i] == '\0')
2190Sstevel@tonic-gate break;
2200Sstevel@tonic-gate /* partial match? peek ahead. */
2210Sstevel@tonic-gate if (*chars_onQ == i) {
2220Sstevel@tonic-gate (*chars_onQ)++;
2230Sstevel@tonic-gate inputQ[i] = (blockpeek) ?
224*9694SScott.Rotondo@Sun.COM _pk() : _fpk();
2250Sstevel@tonic-gate switch ((int)inputQ[i]) {
2260Sstevel@tonic-gate case -2:
2270Sstevel@tonic-gate /*
2280Sstevel@tonic-gate * Since -2 signifies a timeout we don't really
2290Sstevel@tonic-gate * want to put it on the queue so we decrement
2300Sstevel@tonic-gate * our counter.
2310Sstevel@tonic-gate */
2320Sstevel@tonic-gate (*chars_onQ)--;
2330Sstevel@tonic-gate #ifdef DEBUG
2340Sstevel@tonic-gate if (outf)
2350Sstevel@tonic-gate fprintf(outf, "Timed out\n");
2360Sstevel@tonic-gate #endif /* DEBUG */
2370Sstevel@tonic-gate if (flag & _MACRO) {
2380Sstevel@tonic-gate #ifdef DEBUG
2390Sstevel@tonic-gate if (outf)
2400Sstevel@tonic-gate fprintf(outf,
2410Sstevel@tonic-gate "Found macro\n");
2420Sstevel@tonic-gate #endif /* DEBUG */
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate * We have to decrement one because key will be
2450Sstevel@tonic-gate * incremented at the bottom of the out loop.
2460Sstevel@tonic-gate */
2470Sstevel@tonic-gate key = (first = blockpeek =
2480Sstevel@tonic-gate cur_term->_first_macro) -
2490Sstevel@tonic-gate 1;
2500Sstevel@tonic-gate goto outerloop;
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate /*FALLTHROUGH*/
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate case -1:
2560Sstevel@tonic-gate goto ret;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate /* not this one? */
2610Sstevel@tonic-gate if (kp[key]->_sends[i] != inputQ[i])
2620Sstevel@tonic-gate goto outerloop;
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate /* SS-mouse */
2660Sstevel@tonic-gate if (kp[key]->_keyval == KEY_MOUSE) {
2670Sstevel@tonic-gate MOUSE_STATUS old_mouse;
2680Sstevel@tonic-gate int rc;
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate old_mouse = Mouse_status;
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /* read the mouse status information */
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate if (mouse_info)
2750Sstevel@tonic-gate rc = -3; /* NOT IMPLEMENTED */
2760Sstevel@tonic-gate else
2770Sstevel@tonic-gate rc = get_xterm_mouse(blockpeek, &i);
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate if (rc == -1) /* read error */
2800Sstevel@tonic-gate goto ret;
2810Sstevel@tonic-gate else if (rc == -2 || rc == -3) /* timeout */
2820Sstevel@tonic-gate /* or not mouse */
2830Sstevel@tonic-gate goto outerloop;
2840Sstevel@tonic-gate else if (rc == 0) /* report mouse pos */
2850Sstevel@tonic-gate Mouse_status.changes |= 020;
2860Sstevel@tonic-gate else if (rc >= 1 && rc <= 3)
2870Sstevel@tonic-gate /* mouse button event */
2880Sstevel@tonic-gate Mouse_status.changes =
2890Sstevel@tonic-gate (((MOUSE_X_POS != old_mouse.x ||
2900Sstevel@tonic-gate MOUSE_Y_POS != old_mouse.y) << 3) |
2910Sstevel@tonic-gate ((Mouse_status.button[2] !=
2920Sstevel@tonic-gate old_mouse.button[2]) << 2) |
2930Sstevel@tonic-gate ((Mouse_status.button[1] !=
2940Sstevel@tonic-gate old_mouse.button[1]) << 1) |
2950Sstevel@tonic-gate (Mouse_status.button[0] !=
2960Sstevel@tonic-gate old_mouse.button[0]));
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate /* We found it! Read in any chars left in _sends */
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate if ((collapse = i) == INP_QSIZE)
3020Sstevel@tonic-gate for (; kp[key]->_sends[i]; i++)
3030Sstevel@tonic-gate (void) _fpk();
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate /* move key to top of ordered list */
3060Sstevel@tonic-gate if (key != first) {
3070Sstevel@tonic-gate _KEY_MAP *savekey = kp[key];
3080Sstevel@tonic-gate short *lorder;
3090Sstevel@tonic-gate int j;
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate if (key > cur_term->_first_macro)
3120Sstevel@tonic-gate lorder = &(cur_term->_lastmacro_ordered);
3130Sstevel@tonic-gate else
3140Sstevel@tonic-gate lorder = &(cur_term->_lastkey_ordered);
3150Sstevel@tonic-gate /*
3160Sstevel@tonic-gate * If we're below the last ordered key, swap next unordered
3170Sstevel@tonic-gate * key with this one and ripple from there.
3180Sstevel@tonic-gate */
3190Sstevel@tonic-gate if (key > *lorder)
3200Sstevel@tonic-gate kp[key] = kp[(i = ++(*lorder))];
3210Sstevel@tonic-gate else
3220Sstevel@tonic-gate i = key;
3230Sstevel@tonic-gate /* ripple the ordered keys down */
3240Sstevel@tonic-gate for (j = i--; j > first; )
3250Sstevel@tonic-gate kp[j--] = kp[i--];
3260Sstevel@tonic-gate kp[first] = savekey;
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate *inp = kp[first]->_keyval;
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate /*
3310Sstevel@tonic-gate * SS-mouse support: if mouse button event
3320Sstevel@tonic-gate * occured on top of the soft label, we may
3330Sstevel@tonic-gate * have to return the function key corresponding
3340Sstevel@tonic-gate * to that soft label
3350Sstevel@tonic-gate */
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate if (*inp == KEY_MOUSE && A_BUTTON_CHANGED &&
3380Sstevel@tonic-gate (MOUSE_Y_POS == LINES) &&
3390Sstevel@tonic-gate (SP->slk != (SLK_MAP *) NULL) &&
3400Sstevel@tonic-gate (SP->_map_mbe_to_key != 0)) {
3410Sstevel@tonic-gate _map_button(inp);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate goto ret;
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate outerloop:
3470Sstevel@tonic-gate ;
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate ret:
3510Sstevel@tonic-gate /* key not found */
3520Sstevel@tonic-gate #ifdef DEBUG
3530Sstevel@tonic-gate if (outf)
3540Sstevel@tonic-gate if (key == num_keys)
3550Sstevel@tonic-gate fprintf(outf, "Did not match anything.\n");
3560Sstevel@tonic-gate #endif /* DEBUG */
3570Sstevel@tonic-gate return (collapse);
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate /* SS-mouse */
3620Sstevel@tonic-gate /* this function tries to read in information that follows KEY_MOUSE: */
3630Sstevel@tonic-gate /* the first character identifies what button is involved (1,2,or 3) */
3640Sstevel@tonic-gate /* if the first character is 0, we are dealing with report_mouse_pos */
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate * The routine returns the following:
3670Sstevel@tonic-gate * -3: not a mouse button event
3680Sstevel@tonic-gate * -2: read timed out
3690Sstevel@tonic-gate * -1: the read failed
3700Sstevel@tonic-gate * [0, 1, 2, 3] - the first character in the mouse event
3710Sstevel@tonic-gate */
3720Sstevel@tonic-gate static int
get_xterm_mouse(int blockpeek,int * i)3730Sstevel@tonic-gate get_xterm_mouse(int blockpeek, int *i)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate chtype *inputQ = cur_term->_input_queue; /* ??? */
3760Sstevel@tonic-gate /* LINTED */
3770Sstevel@tonic-gate chtype *chars_onQ = (chtype *) &(cur_term->_chars_on_queue);
3780Sstevel@tonic-gate int j, mx, my;
3790Sstevel@tonic-gate int char1, char2, c1, c2;
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate /* the first character should be 0, 1, 2, or 4 */
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate char1 = (inputQ[(*i)++] = (blockpeek) ? _pk() : _fpk());
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate /* read error or timeout */
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate if (char1 < 0)
3880Sstevel@tonic-gate return (char1);
3890Sstevel@tonic-gate (*chars_onQ)++;
3900Sstevel@tonic-gate
3910Sstevel@tonic-gate if (char1 < '0' || char1 > '3')
3920Sstevel@tonic-gate return (-3);
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate /* if the character is 1, 2, or 3 it must be followed by */
3950Sstevel@tonic-gate /* P, R, C, D, or T */
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate if (char1 != '0') {
3980Sstevel@tonic-gate char2 = (inputQ[(*i)++] = (blockpeek) ? _pk() : _fpk());
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate if (char2 < 0)
4010Sstevel@tonic-gate return (char2);
4020Sstevel@tonic-gate
4030Sstevel@tonic-gate (*chars_onQ)++;
4040Sstevel@tonic-gate if (char2 != 'P' && char2 != 'R' && char2 != 'C' &&
4050Sstevel@tonic-gate char2 != 'D' && char2 != 'T')
4060Sstevel@tonic-gate return (-3);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate /* read X and Y coordinates of the mouse */
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate for (j = 0; j < 2; j++) {
4120Sstevel@tonic-gate c1 = (inputQ[(*i)++] = (blockpeek) ? _pk() : _fpk());
4130Sstevel@tonic-gate if (c1 < 0)
4140Sstevel@tonic-gate return (c1);
4150Sstevel@tonic-gate (*chars_onQ)++;
4160Sstevel@tonic-gate if (c1 >= ' ' && c1 <= '~') { /* ascii char */
4170Sstevel@tonic-gate if (j == 0)
4180Sstevel@tonic-gate mx = c1 - ' ';
4190Sstevel@tonic-gate else
4200Sstevel@tonic-gate my = c1 - ' ';
4210Sstevel@tonic-gate } else if (char1 == 01 || char1 == 02) { /* ^A || ^B */
4220Sstevel@tonic-gate c2 = (inputQ[(*i)++] = (blockpeek) ? _pk() : _fpk());
4230Sstevel@tonic-gate if (c2 < 0)
4240Sstevel@tonic-gate return (c2);
4250Sstevel@tonic-gate (*chars_onQ)++;
4260Sstevel@tonic-gate if (c2 >= ' ' && c2 <= '~') {
4270Sstevel@tonic-gate if (j == 0)
4280Sstevel@tonic-gate mx = c1 * (c2 - ' ');
4290Sstevel@tonic-gate else
4300Sstevel@tonic-gate my = c1 * (c2 - ' ');
4310Sstevel@tonic-gate } else
4320Sstevel@tonic-gate return (-3);
4330Sstevel@tonic-gate } else
4340Sstevel@tonic-gate return (-3);
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate /* read complete mouse event: update the Mouse_status structure */
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate MOUSE_X_POS = mx;
4400Sstevel@tonic-gate MOUSE_Y_POS = my;
4410Sstevel@tonic-gate j = char1 - '0';
4420Sstevel@tonic-gate if (j != 0) {
4430Sstevel@tonic-gate switch (char2) {
4440Sstevel@tonic-gate case 'P':
4450Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_PRESSED;
4460Sstevel@tonic-gate break;
4470Sstevel@tonic-gate case 'R':
4480Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_RELEASED;
4490Sstevel@tonic-gate break;
4500Sstevel@tonic-gate case 'C':
4510Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_CLICKED;
4520Sstevel@tonic-gate break;
4530Sstevel@tonic-gate case 'D':
4540Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_DOUBLE_CLICKED;
4550Sstevel@tonic-gate break;
4560Sstevel@tonic-gate case 'T':
4570Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_TRIPLE_CLICKED;
4580Sstevel@tonic-gate break;
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate return (j);
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate /* SS-mouse-end */
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate /*
4670Sstevel@tonic-gate * Fast peek key. Like getchar but if the right flags are set, times out
4680Sstevel@tonic-gate * quickly if there is nothing waiting, returning -1.
4690Sstevel@tonic-gate * f is an output stdio descriptor, we read from the fileno.
4700Sstevel@tonic-gate * We wait for long enough for a terminal to send another character
4710Sstevel@tonic-gate * (at 15cps repeat rate, this is 67 ms, I'm using 100ms to allow
4720Sstevel@tonic-gate * a bit of a fudge factor) and time out more quickly.
4730Sstevel@tonic-gate * -2 is returned if we time out, -1 is returned if interrupted, and the
4740Sstevel@tonic-gate * character is returned otherwise.
4750Sstevel@tonic-gate */
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate #ifndef FIONREAD
4780Sstevel@tonic-gate
4790Sstevel@tonic-gate /*
4800Sstevel@tonic-gate * Traditional implementation. The best resolution we have is 1 second,
4810Sstevel@tonic-gate * so we set a 1 second alarm and try to read. If we fail for 1 second,
4820Sstevel@tonic-gate * we assume there is no key waiting. Problem here is that 1 second is
4830Sstevel@tonic-gate * too long; people can type faster than this.
4840Sstevel@tonic-gate *
4850Sstevel@tonic-gate * Another possible implementation of changing VMIN/VTIME before and
4860Sstevel@tonic-gate * after each read does not work because the tty driver's timeout
4870Sstevel@tonic-gate * mechanism is too unreliable when the timeouts are changed too quickly.
4880Sstevel@tonic-gate */
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate static char sig_caught;
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate static
4930Sstevel@tonic-gate #ifdef SIGPOLL /* Vr3 and beyond */
4940Sstevel@tonic-gate void
4950Sstevel@tonic-gate #endif /* SIGPOLL */
4960Sstevel@tonic-gate /* The following line causes a lint warning for "dummy" which is not used. */
_catch_alarm(int dummy)4970Sstevel@tonic-gate _catch_alarm(int dummy)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate sig_caught = 1;
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate static int
_fpk(void)5030Sstevel@tonic-gate _fpk(void)
5040Sstevel@tonic-gate {
5050Sstevel@tonic-gate unsigned char c;
5060Sstevel@tonic-gate int infd = cur_term->_inputfd;
5070Sstevel@tonic-gate ssize_t rc;
5080Sstevel@tonic-gate #ifdef SIGPOLL /* Vr3 and beyond */
5090Sstevel@tonic-gate void (*oldsig)(int);
5100Sstevel@tonic-gate #else /* SIGPOLL */
5110Sstevel@tonic-gate int (*oldsig)(int);
5120Sstevel@tonic-gate #endif /* SIGPOLL */
5130Sstevel@tonic-gate unsigned int oldalarm, alarm(unsigned);
5140Sstevel@tonic-gate
5150Sstevel@tonic-gate /* turn off any user alarms and set our own */
5160Sstevel@tonic-gate oldalarm = alarm(0);
5170Sstevel@tonic-gate sig_caught = 0;
5180Sstevel@tonic-gate oldsig = signal(SIGALRM, _catch_alarm);
5190Sstevel@tonic-gate (void) alarm(1);
5200Sstevel@tonic-gate rc = read(cur_term->_inputfd, (char *)&c, 1);
5210Sstevel@tonic-gate (void) alarm(0);
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate /*
5240Sstevel@tonic-gate * This code is to take care of the possibility of
5250Sstevel@tonic-gate * the process getting swapped out in the middle of
5260Sstevel@tonic-gate * read() call above. The interrupt will cause the
5270Sstevel@tonic-gate * read() call to retur, even if a character is really
5280Sstevel@tonic-gate * on the clist. So we do a non-blocking read() to make
5290Sstevel@tonic-gate * sure that there really isn't a character there.
5300Sstevel@tonic-gate */
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate if (sig_caught && rc != 1)
5330Sstevel@tonic-gate if (cur_term->_check_fd != -1)
5340Sstevel@tonic-gate rc = read(cur_term->_check_fd, (char *)&c, 1);
5350Sstevel@tonic-gate else {
5360Sstevel@tonic-gate #include <fcntl.h>
5370Sstevel@tonic-gate int fcflags = fcntl(infd, F_GETFL, 0);
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate (void) fcntl(infd, F_SETFL, fcflags | O_NDELAY);
5400Sstevel@tonic-gate rc = read(infd, (char *)&c, 1);
5410Sstevel@tonic-gate (void) fcntl(infd, F_SETFL, fcflags);
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate /* restore the user alarms */
5450Sstevel@tonic-gate (void) signal(SIGALRM, oldsig);
5460Sstevel@tonic-gate if (sig_caught && oldalarm > 1)
547*9694SScott.Rotondo@Sun.COM oldalarm--;
5480Sstevel@tonic-gate (void) alarm(oldalarm);
5490Sstevel@tonic-gate if (rc == 1) /* got a character */
550*9694SScott.Rotondo@Sun.COM return (c);
5510Sstevel@tonic-gate else
552*9694SScott.Rotondo@Sun.COM if (sig_caught) /* timed out */
553*9694SScott.Rotondo@Sun.COM return (-2);
554*9694SScott.Rotondo@Sun.COM else /* EOF or got interrupted */
555*9694SScott.Rotondo@Sun.COM return (-1);
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate #else /* FIONREAD */
5580Sstevel@tonic-gate /*
5590Sstevel@tonic-gate * If we have the select system call, we can do much better than the
5600Sstevel@tonic-gate * traditional method. Even if we don't have the real 4.2BSD select, we
5610Sstevel@tonic-gate * can emulate it with napms and FIONREAD. napms might be done with only
5620Sstevel@tonic-gate * 1 second resolution, but this is no worse than what we have in the
5630Sstevel@tonic-gate * traditional implementation.
5640Sstevel@tonic-gate */
5650Sstevel@tonic-gate static
_fpk()5660Sstevel@tonic-gate _fpk()
5670Sstevel@tonic-gate {
5680Sstevel@tonic-gate int infd, rc;
5690Sstevel@tonic-gate int *outfd, *exfd;
5700Sstevel@tonic-gate unsigned char c;
5710Sstevel@tonic-gate struct timeval t;
5720Sstevel@tonic-gate
5730Sstevel@tonic-gate infd = 1 << cur_term->_inputfd;
5740Sstevel@tonic-gate outfd = exfd = (int *)NULL;
5750Sstevel@tonic-gate t.tv_sec = 0;
5760Sstevel@tonic-gate t.tv_usec = 100000; /* 100 milliseconds */
5770Sstevel@tonic-gate rc = select(20, &infd, outfd, exfd, &t);
5780Sstevel@tonic-gate if (rc < 0)
5790Sstevel@tonic-gate return (-2);
5800Sstevel@tonic-gate rc = read(fileno(f), &c, 1);
5810Sstevel@tonic-gate return (rc == 1 ? c : -1);
5820Sstevel@tonic-gate }
5830Sstevel@tonic-gate #endif /* FIONREAD */
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate /*
5860Sstevel@tonic-gate * Plain peekchar function. Nothing fancy. This is just like _fpk
5870Sstevel@tonic-gate * but will wait forever rather than time out.
5880Sstevel@tonic-gate */
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate static int
_pk(void)5910Sstevel@tonic-gate _pk(void)
5920Sstevel@tonic-gate {
5930Sstevel@tonic-gate unsigned char c;
5940Sstevel@tonic-gate
5950Sstevel@tonic-gate return ((read(cur_term->_inputfd, (char *)&c, 1) == 1) ? c : ERR);
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate /*
6000Sstevel@tonic-gate * SS-mouse: check if this mouse button event should map into
6010Sstevel@tonic-gate * function key
6020Sstevel@tonic-gate */
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate static void
_map_button(chtype * inp)6060Sstevel@tonic-gate _map_button(chtype *inp)
6070Sstevel@tonic-gate {
6080Sstevel@tonic-gate SLK_MAP *slk = SP->slk;
6090Sstevel@tonic-gate int num = slk->_num;
6100Sstevel@tonic-gate int len = slk->_len;
6110Sstevel@tonic-gate int i;
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate /* first determine if this mouse button event should be */
6140Sstevel@tonic-gate /* mapped into function key */
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate if (!(SP->_map_mbe_to_key &
6170Sstevel@tonic-gate ((BUTTON_CHANGED(3) << (10 + BUTTON_STATUS(3))) |
6180Sstevel@tonic-gate (BUTTON_CHANGED(2) << (5 + BUTTON_STATUS(2))) |
6190Sstevel@tonic-gate (BUTTON_CHANGED(1) << BUTTON_STATUS(1)))))
6200Sstevel@tonic-gate return;
6210Sstevel@tonic-gate
6220Sstevel@tonic-gate for (i = 0; i < num; i++) {
6230Sstevel@tonic-gate if (MOUSE_X_POS < slk->_labx[i])
6240Sstevel@tonic-gate break;
6250Sstevel@tonic-gate if (MOUSE_X_POS > slk->_labx[i] + len)
6260Sstevel@tonic-gate continue;
6270Sstevel@tonic-gate *inp = KEY_F(1) + i;
6280Sstevel@tonic-gate break;
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate }
631