1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* 31*7c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988 32*7c478bd9Sstevel@tonic-gate * The Regents of the University of California 33*7c478bd9Sstevel@tonic-gate * All Rights Reserved 34*7c478bd9Sstevel@tonic-gate * 35*7c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from 36*7c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its 37*7c478bd9Sstevel@tonic-gate * contributors. 38*7c478bd9Sstevel@tonic-gate */ 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #include "curses_inc.h" 45*7c478bd9Sstevel@tonic-gate #include <signal.h> 46*7c478bd9Sstevel@tonic-gate #include <unistd.h> 47*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 48*7c478bd9Sstevel@tonic-gate #include <ctype.h> 49*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate /* 52*7c478bd9Sstevel@tonic-gate * Read a key typed from the terminal 53*7c478bd9Sstevel@tonic-gate * 54*7c478bd9Sstevel@tonic-gate * interpret: = 0 for single-char key only 55*7c478bd9Sstevel@tonic-gate * = 1 for matching function key and macro patterns. 56*7c478bd9Sstevel@tonic-gate * = 2 same as 1 but no time-out for funckey matching. 57*7c478bd9Sstevel@tonic-gate */ 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate static int _getkey(int, chtype *); 60*7c478bd9Sstevel@tonic-gate static int _fpk(void); 61*7c478bd9Sstevel@tonic-gate static int _pk(void); 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate chtype 64*7c478bd9Sstevel@tonic-gate tgetch(int interpret) 65*7c478bd9Sstevel@tonic-gate { 66*7c478bd9Sstevel@tonic-gate int i = 0, j, collapse = 1; 67*7c478bd9Sstevel@tonic-gate #define WAIT3 333 68*7c478bd9Sstevel@tonic-gate chtype inp; 69*7c478bd9Sstevel@tonic-gate chtype *inputQ = cur_term->_input_queue; 70*7c478bd9Sstevel@tonic-gate char *chars_onQ = &(cur_term->_chars_on_queue); 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate #ifdef SYSV 73*7c478bd9Sstevel@tonic-gate /* 74*7c478bd9Sstevel@tonic-gate * Register the fact that getch is being used so 75*7c478bd9Sstevel@tonic-gate * that typeahead checking can be done. 76*7c478bd9Sstevel@tonic-gate * This code should GO AWAY when a poll() or FIONREAD can 77*7c478bd9Sstevel@tonic-gate * be done on the file descriptor as then the check 78*7c478bd9Sstevel@tonic-gate * will be non-destructive. 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate cur_term->fl_typeahdok = TRUE; 81*7c478bd9Sstevel@tonic-gate #endif /* SYSV */ 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate /* ask for input */ 84*7c478bd9Sstevel@tonic-gate if (cur_term->_ungotten > 0) { 85*7c478bd9Sstevel@tonic-gate cur_term->_ungotten--; 86*7c478bd9Sstevel@tonic-gate /* decode an ungetch()'d character */ 87*7c478bd9Sstevel@tonic-gate inp = -inputQ[0]; 88*7c478bd9Sstevel@tonic-gate } else { 89*7c478bd9Sstevel@tonic-gate /* Only read a character if there is no typeahead/peekahead. */ 90*7c478bd9Sstevel@tonic-gate if (*chars_onQ == 0) { 91*7c478bd9Sstevel@tonic-gate /* (*chars_onQ)++; MR */ 92*7c478bd9Sstevel@tonic-gate #ifdef FIONREAD 93*7c478bd9Sstevel@tonic-gate inp = _readchar(); 94*7c478bd9Sstevel@tonic-gate #else /* FIONREAD */ 95*7c478bd9Sstevel@tonic-gate inp = (chtype) _pk(); 96*7c478bd9Sstevel@tonic-gate if ((int)inp == ERR) { 97*7c478bd9Sstevel@tonic-gate /* 98*7c478bd9Sstevel@tonic-gate * interpret is set to 0 so that down below we don't 99*7c478bd9Sstevel@tonic-gate * drop into getkey since we already know there can't be 100*7c478bd9Sstevel@tonic-gate * a key that starts with -1. Also, we don't want to 101*7c478bd9Sstevel@tonic-gate * access funckeystarter[-1]. 102*7c478bd9Sstevel@tonic-gate */ 103*7c478bd9Sstevel@tonic-gate interpret = FALSE; 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate #endif /* FIONREAD */ 106*7c478bd9Sstevel@tonic-gate (*chars_onQ)++; 107*7c478bd9Sstevel@tonic-gate } else 108*7c478bd9Sstevel@tonic-gate inp = inputQ[0]; 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 111*7c478bd9Sstevel@tonic-gate if (outf) 112*7c478bd9Sstevel@tonic-gate fprintf(outf, "TGETCH read '%s'\n", unctrl(inp)); 113*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate /* Check for arrow and function keys */ 116*7c478bd9Sstevel@tonic-gate if (interpret && cur_term->funckeystarter[inp]) 117*7c478bd9Sstevel@tonic-gate collapse = _getkey(interpret - 1, &inp); 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate /* Collapse the input queue to remove the escape */ 121*7c478bd9Sstevel@tonic-gate /* sequence from the stack. */ 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate j = *chars_onQ; 124*7c478bd9Sstevel@tonic-gate (*chars_onQ) -= collapse; 125*7c478bd9Sstevel@tonic-gate while (collapse < j) 126*7c478bd9Sstevel@tonic-gate inputQ[i++] = inputQ[collapse++]; 127*7c478bd9Sstevel@tonic-gate return (inp); 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate #ifdef FIONREAD 131*7c478bd9Sstevel@tonic-gate static int 132*7c478bd9Sstevel@tonic-gate _readchar() 133*7c478bd9Sstevel@tonic-gate { 134*7c478bd9Sstevel@tonic-gate int i; 135*7c478bd9Sstevel@tonic-gate unsigned char c; 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate if (cur_term->_delay == 0) { 138*7c478bd9Sstevel@tonic-gate int arg; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate (void) ioctl(cur_term->_inputfd, FIONREAD, &arg); 141*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 142*7c478bd9Sstevel@tonic-gate if (outf) 143*7c478bd9Sstevel@tonic-gate fprintf(outf, "FIONREAD returns %d\n", arg); 144*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 145*7c478bd9Sstevel@tonic-gate if (arg < 1) 146*7c478bd9Sstevel@tonic-gate return (-1); 147*7c478bd9Sstevel@tonic-gate } else 148*7c478bd9Sstevel@tonic-gate if (cur_term->_delay > 0) { 149*7c478bd9Sstevel@tonic-gate char c; 150*7c478bd9Sstevel@tonic-gate int infd; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate infd = 1 << cur_term->_inputfd; 153*7c478bd9Sstevel@tonic-gate t.tv_sec = cur_term->_delay / 1000; 154*7c478bd9Sstevel@tonic-gate t.tv_usec = (cur_term->_delay % 1000) * 1000; 155*7c478bd9Sstevel@tonic-gate i = select(20, &infd, (int *)NULL, (int *)NULL, &t); 156*7c478bd9Sstevel@tonic-gate if (i < 0) 157*7c478bd9Sstevel@tonic-gate return (ERR); 158*7c478bd9Sstevel@tonic-gate i = read(cur_term->_inputfd, &c, 1); 159*7c478bd9Sstevel@tonic-gate } else 160*7c478bd9Sstevel@tonic-gate i = read(cur_term->_inputfd, &c, 1); 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 163*7c478bd9Sstevel@tonic-gate if (outf) 164*7c478bd9Sstevel@tonic-gate fprintf(outf, "read from %d returns %d chars, first %o\n", 165*7c478bd9Sstevel@tonic-gate cur_term->_inputfd, i, c); 166*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate if (i > 0) 169*7c478bd9Sstevel@tonic-gate return (c); 170*7c478bd9Sstevel@tonic-gate else 171*7c478bd9Sstevel@tonic-gate return (ERR); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate #endif /* !FIONREAD */ 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 176*7c478bd9Sstevel@tonic-gate extern char *_asciify(); 177*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate /* 180*7c478bd9Sstevel@tonic-gate * This algorithm is a "learning" algorithm. The premise is 181*7c478bd9Sstevel@tonic-gate * that keys used once are like to be used again and again. 182*7c478bd9Sstevel@tonic-gate * Since the time for a linear search of the table is so 183*7c478bd9Sstevel@tonic-gate * expensive, we move keys that are found up to the top of 184*7c478bd9Sstevel@tonic-gate * the list, making the access to a repeated key very fast and 185*7c478bd9Sstevel@tonic-gate * keys that have been used before close to the top. 186*7c478bd9Sstevel@tonic-gate */ 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate static int 189*7c478bd9Sstevel@tonic-gate _getkey(int blockpeek, chtype *inp) 190*7c478bd9Sstevel@tonic-gate { 191*7c478bd9Sstevel@tonic-gate _KEY_MAP **kp = cur_term->_keys; 192*7c478bd9Sstevel@tonic-gate int key, num_keys = cur_term->_ksz; 193*7c478bd9Sstevel@tonic-gate int i; 194*7c478bd9Sstevel@tonic-gate chtype *inputQ = cur_term->_input_queue; 195*7c478bd9Sstevel@tonic-gate char *chars_onQ = &(cur_term->_chars_on_queue), 196*7c478bd9Sstevel@tonic-gate flag = cur_term->funckeystarter[*inp]; 197*7c478bd9Sstevel@tonic-gate int first, collapse = 1; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 201*7c478bd9Sstevel@tonic-gate if (outf) 202*7c478bd9Sstevel@tonic-gate fprintf(outf, "getkey(): looking in linear table, " 203*7c478bd9Sstevel@tonic-gate "inp=%d\n", *inp); 204*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate if (flag & _KEY) 207*7c478bd9Sstevel@tonic-gate key = 0; 208*7c478bd9Sstevel@tonic-gate else { 209*7c478bd9Sstevel@tonic-gate key = cur_term->_first_macro; 210*7c478bd9Sstevel@tonic-gate blockpeek = TRUE; 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate first = key; 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate for (; key < num_keys; key++) { 215*7c478bd9Sstevel@tonic-gate if (kp[key]->_sends[0] == *inp) { 216*7c478bd9Sstevel@tonic-gate for (i = 1; i < INP_QSIZE; i++) { 217*7c478bd9Sstevel@tonic-gate /* found it? */ 218*7c478bd9Sstevel@tonic-gate if (kp[key]->_sends[i] == '\0') 219*7c478bd9Sstevel@tonic-gate break; 220*7c478bd9Sstevel@tonic-gate /* partial match? peek ahead. */ 221*7c478bd9Sstevel@tonic-gate if (*chars_onQ == i) { 222*7c478bd9Sstevel@tonic-gate (*chars_onQ)++; 223*7c478bd9Sstevel@tonic-gate inputQ[i] = (blockpeek) ? 224*7c478bd9Sstevel@tonic-gate _pk() : _fpk(); 225*7c478bd9Sstevel@tonic-gate switch ((int)inputQ[i]) { 226*7c478bd9Sstevel@tonic-gate case -2: 227*7c478bd9Sstevel@tonic-gate /* 228*7c478bd9Sstevel@tonic-gate * Since -2 signifies a timeout we don't really 229*7c478bd9Sstevel@tonic-gate * want to put it on the queue so we decrement 230*7c478bd9Sstevel@tonic-gate * our counter. 231*7c478bd9Sstevel@tonic-gate */ 232*7c478bd9Sstevel@tonic-gate (*chars_onQ)--; 233*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 234*7c478bd9Sstevel@tonic-gate if (outf) 235*7c478bd9Sstevel@tonic-gate fprintf(outf, "Timed out\n"); 236*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 237*7c478bd9Sstevel@tonic-gate if (flag & _MACRO) { 238*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 239*7c478bd9Sstevel@tonic-gate if (outf) 240*7c478bd9Sstevel@tonic-gate fprintf(outf, 241*7c478bd9Sstevel@tonic-gate "Found macro\n"); 242*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 243*7c478bd9Sstevel@tonic-gate /* 244*7c478bd9Sstevel@tonic-gate * We have to decrement one because key will be 245*7c478bd9Sstevel@tonic-gate * incremented at the bottom of the out loop. 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate key = (first = blockpeek = 248*7c478bd9Sstevel@tonic-gate cur_term->_first_macro) - 249*7c478bd9Sstevel@tonic-gate 1; 250*7c478bd9Sstevel@tonic-gate goto outerloop; 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate case -1: 256*7c478bd9Sstevel@tonic-gate goto ret; 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate /* not this one? */ 261*7c478bd9Sstevel@tonic-gate if (kp[key]->_sends[i] != inputQ[i]) 262*7c478bd9Sstevel@tonic-gate goto outerloop; 263*7c478bd9Sstevel@tonic-gate } 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate /* SS-mouse */ 266*7c478bd9Sstevel@tonic-gate if (kp[key]->_keyval == KEY_MOUSE) { 267*7c478bd9Sstevel@tonic-gate MOUSE_STATUS old_mouse; 268*7c478bd9Sstevel@tonic-gate int rc; 269*7c478bd9Sstevel@tonic-gate static int get_xterm_mouse(int, int *); 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate old_mouse = Mouse_status; 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate /* read the mouse status information */ 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate if (mouse_info) 276*7c478bd9Sstevel@tonic-gate rc = -3; /* NOT IMPLEMENTED */ 277*7c478bd9Sstevel@tonic-gate else 278*7c478bd9Sstevel@tonic-gate rc = get_xterm_mouse(blockpeek, &i); 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate if (rc == -1) /* read error */ 281*7c478bd9Sstevel@tonic-gate goto ret; 282*7c478bd9Sstevel@tonic-gate else if (rc == -2 || rc == -3) /* timeout */ 283*7c478bd9Sstevel@tonic-gate /* or not mouse */ 284*7c478bd9Sstevel@tonic-gate goto outerloop; 285*7c478bd9Sstevel@tonic-gate else if (rc == 0) /* report mouse pos */ 286*7c478bd9Sstevel@tonic-gate Mouse_status.changes |= 020; 287*7c478bd9Sstevel@tonic-gate else if (rc >= 1 && rc <= 3) 288*7c478bd9Sstevel@tonic-gate /* mouse button event */ 289*7c478bd9Sstevel@tonic-gate Mouse_status.changes = 290*7c478bd9Sstevel@tonic-gate (((MOUSE_X_POS != old_mouse.x || 291*7c478bd9Sstevel@tonic-gate MOUSE_Y_POS != old_mouse.y) << 3) | 292*7c478bd9Sstevel@tonic-gate ((Mouse_status.button[2] != 293*7c478bd9Sstevel@tonic-gate old_mouse.button[2]) << 2) | 294*7c478bd9Sstevel@tonic-gate ((Mouse_status.button[1] != 295*7c478bd9Sstevel@tonic-gate old_mouse.button[1]) << 1) | 296*7c478bd9Sstevel@tonic-gate (Mouse_status.button[0] != 297*7c478bd9Sstevel@tonic-gate old_mouse.button[0])); 298*7c478bd9Sstevel@tonic-gate } 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate /* We found it! Read in any chars left in _sends */ 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate if ((collapse = i) == INP_QSIZE) 303*7c478bd9Sstevel@tonic-gate for (; kp[key]->_sends[i]; i++) 304*7c478bd9Sstevel@tonic-gate (void) _fpk(); 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate /* move key to top of ordered list */ 307*7c478bd9Sstevel@tonic-gate if (key != first) { 308*7c478bd9Sstevel@tonic-gate _KEY_MAP *savekey = kp[key]; 309*7c478bd9Sstevel@tonic-gate short *lorder; 310*7c478bd9Sstevel@tonic-gate int j; 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate if (key > cur_term->_first_macro) 313*7c478bd9Sstevel@tonic-gate lorder = &(cur_term->_lastmacro_ordered); 314*7c478bd9Sstevel@tonic-gate else 315*7c478bd9Sstevel@tonic-gate lorder = &(cur_term->_lastkey_ordered); 316*7c478bd9Sstevel@tonic-gate /* 317*7c478bd9Sstevel@tonic-gate * If we're below the last ordered key, swap next unordered 318*7c478bd9Sstevel@tonic-gate * key with this one and ripple from there. 319*7c478bd9Sstevel@tonic-gate */ 320*7c478bd9Sstevel@tonic-gate if (key > *lorder) 321*7c478bd9Sstevel@tonic-gate kp[key] = kp[(i = ++(*lorder))]; 322*7c478bd9Sstevel@tonic-gate else 323*7c478bd9Sstevel@tonic-gate i = key; 324*7c478bd9Sstevel@tonic-gate /* ripple the ordered keys down */ 325*7c478bd9Sstevel@tonic-gate for (j = i--; j > first; ) 326*7c478bd9Sstevel@tonic-gate kp[j--] = kp[i--]; 327*7c478bd9Sstevel@tonic-gate kp[first] = savekey; 328*7c478bd9Sstevel@tonic-gate } 329*7c478bd9Sstevel@tonic-gate *inp = kp[first]->_keyval; 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * SS-mouse support: if mouse button event 333*7c478bd9Sstevel@tonic-gate * occured on top of the soft label, we may 334*7c478bd9Sstevel@tonic-gate * have to return the function key corresponding 335*7c478bd9Sstevel@tonic-gate * to that soft label 336*7c478bd9Sstevel@tonic-gate */ 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate if (*inp == KEY_MOUSE && A_BUTTON_CHANGED && 339*7c478bd9Sstevel@tonic-gate (MOUSE_Y_POS == LINES) && 340*7c478bd9Sstevel@tonic-gate (SP->slk != (SLK_MAP *) NULL) && 341*7c478bd9Sstevel@tonic-gate (SP->_map_mbe_to_key != 0)) { 342*7c478bd9Sstevel@tonic-gate static void _map_button(chtype *); 343*7c478bd9Sstevel@tonic-gate _map_button(inp); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate goto ret; 347*7c478bd9Sstevel@tonic-gate } 348*7c478bd9Sstevel@tonic-gate outerloop: 349*7c478bd9Sstevel@tonic-gate ; 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate ret: 353*7c478bd9Sstevel@tonic-gate /* key not found */ 354*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 355*7c478bd9Sstevel@tonic-gate if (outf) 356*7c478bd9Sstevel@tonic-gate if (key == num_keys) 357*7c478bd9Sstevel@tonic-gate fprintf(outf, "Did not match anything.\n"); 358*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 359*7c478bd9Sstevel@tonic-gate return (collapse); 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate /* SS-mouse */ 364*7c478bd9Sstevel@tonic-gate /* this function tries to read in information that follows KEY_MOUSE: */ 365*7c478bd9Sstevel@tonic-gate /* the first character identifies what button is involved (1,2,or 3) */ 366*7c478bd9Sstevel@tonic-gate /* if the first character is 0, we are dealing with report_mouse_pos */ 367*7c478bd9Sstevel@tonic-gate /* 368*7c478bd9Sstevel@tonic-gate * The routine returns the following: 369*7c478bd9Sstevel@tonic-gate * -3: not a mouse button event 370*7c478bd9Sstevel@tonic-gate * -2: read timed out 371*7c478bd9Sstevel@tonic-gate * -1: the read failed 372*7c478bd9Sstevel@tonic-gate * [0, 1, 2, 3] - the first character in the mouse event 373*7c478bd9Sstevel@tonic-gate */ 374*7c478bd9Sstevel@tonic-gate static int 375*7c478bd9Sstevel@tonic-gate get_xterm_mouse(int blockpeek, int *i) 376*7c478bd9Sstevel@tonic-gate { 377*7c478bd9Sstevel@tonic-gate chtype *inputQ = cur_term->_input_queue; /* ??? */ 378*7c478bd9Sstevel@tonic-gate /* LINTED */ 379*7c478bd9Sstevel@tonic-gate chtype *chars_onQ = (chtype *) &(cur_term->_chars_on_queue); 380*7c478bd9Sstevel@tonic-gate int j, mx, my; 381*7c478bd9Sstevel@tonic-gate int char1, char2, c1, c2; 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate /* the first character should be 0, 1, 2, or 4 */ 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate char1 = (inputQ[(*i)++] = (blockpeek) ? _pk() : _fpk()); 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate /* read error or timeout */ 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate if (char1 < 0) 390*7c478bd9Sstevel@tonic-gate return (char1); 391*7c478bd9Sstevel@tonic-gate (*chars_onQ)++; 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate if (char1 < '0' || char1 > '3') 394*7c478bd9Sstevel@tonic-gate return (-3); 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate /* if the character is 1, 2, or 3 it must be followed by */ 397*7c478bd9Sstevel@tonic-gate /* P, R, C, D, or T */ 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate if (char1 != '0') { 400*7c478bd9Sstevel@tonic-gate char2 = (inputQ[(*i)++] = (blockpeek) ? _pk() : _fpk()); 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate if (char2 < 0) 403*7c478bd9Sstevel@tonic-gate return (char2); 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate (*chars_onQ)++; 406*7c478bd9Sstevel@tonic-gate if (char2 != 'P' && char2 != 'R' && char2 != 'C' && 407*7c478bd9Sstevel@tonic-gate char2 != 'D' && char2 != 'T') 408*7c478bd9Sstevel@tonic-gate return (-3); 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* read X and Y coordinates of the mouse */ 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate for (j = 0; j < 2; j++) { 414*7c478bd9Sstevel@tonic-gate c1 = (inputQ[(*i)++] = (blockpeek) ? _pk() : _fpk()); 415*7c478bd9Sstevel@tonic-gate if (c1 < 0) 416*7c478bd9Sstevel@tonic-gate return (c1); 417*7c478bd9Sstevel@tonic-gate (*chars_onQ)++; 418*7c478bd9Sstevel@tonic-gate if (c1 >= ' ' && c1 <= '~') { /* ascii char */ 419*7c478bd9Sstevel@tonic-gate if (j == 0) 420*7c478bd9Sstevel@tonic-gate mx = c1 - ' '; 421*7c478bd9Sstevel@tonic-gate else 422*7c478bd9Sstevel@tonic-gate my = c1 - ' '; 423*7c478bd9Sstevel@tonic-gate } else if (char1 == 01 || char1 == 02) { /* ^A || ^B */ 424*7c478bd9Sstevel@tonic-gate c2 = (inputQ[(*i)++] = (blockpeek) ? _pk() : _fpk()); 425*7c478bd9Sstevel@tonic-gate if (c2 < 0) 426*7c478bd9Sstevel@tonic-gate return (c2); 427*7c478bd9Sstevel@tonic-gate (*chars_onQ)++; 428*7c478bd9Sstevel@tonic-gate if (c2 >= ' ' && c2 <= '~') { 429*7c478bd9Sstevel@tonic-gate if (j == 0) 430*7c478bd9Sstevel@tonic-gate mx = c1 * (c2 - ' '); 431*7c478bd9Sstevel@tonic-gate else 432*7c478bd9Sstevel@tonic-gate my = c1 * (c2 - ' '); 433*7c478bd9Sstevel@tonic-gate } else 434*7c478bd9Sstevel@tonic-gate return (-3); 435*7c478bd9Sstevel@tonic-gate } else 436*7c478bd9Sstevel@tonic-gate return (-3); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /* read complete mouse event: update the Mouse_status structure */ 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate MOUSE_X_POS = mx; 442*7c478bd9Sstevel@tonic-gate MOUSE_Y_POS = my; 443*7c478bd9Sstevel@tonic-gate j = char1 - '0'; 444*7c478bd9Sstevel@tonic-gate if (j != 0) { 445*7c478bd9Sstevel@tonic-gate switch (char2) { 446*7c478bd9Sstevel@tonic-gate case 'P': 447*7c478bd9Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_PRESSED; 448*7c478bd9Sstevel@tonic-gate break; 449*7c478bd9Sstevel@tonic-gate case 'R': 450*7c478bd9Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_RELEASED; 451*7c478bd9Sstevel@tonic-gate break; 452*7c478bd9Sstevel@tonic-gate case 'C': 453*7c478bd9Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_CLICKED; 454*7c478bd9Sstevel@tonic-gate break; 455*7c478bd9Sstevel@tonic-gate case 'D': 456*7c478bd9Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_DOUBLE_CLICKED; 457*7c478bd9Sstevel@tonic-gate break; 458*7c478bd9Sstevel@tonic-gate case 'T': 459*7c478bd9Sstevel@tonic-gate BUTTON_STATUS(j) = BUTTON_TRIPLE_CLICKED; 460*7c478bd9Sstevel@tonic-gate break; 461*7c478bd9Sstevel@tonic-gate } 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate return (j); 464*7c478bd9Sstevel@tonic-gate } 465*7c478bd9Sstevel@tonic-gate /* SS-mouse-end */ 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate /* 469*7c478bd9Sstevel@tonic-gate * Fast peek key. Like getchar but if the right flags are set, times out 470*7c478bd9Sstevel@tonic-gate * quickly if there is nothing waiting, returning -1. 471*7c478bd9Sstevel@tonic-gate * f is an output stdio descriptor, we read from the fileno. 472*7c478bd9Sstevel@tonic-gate * We wait for long enough for a terminal to send another character 473*7c478bd9Sstevel@tonic-gate * (at 15cps repeat rate, this is 67 ms, I'm using 100ms to allow 474*7c478bd9Sstevel@tonic-gate * a bit of a fudge factor) and time out more quickly. 475*7c478bd9Sstevel@tonic-gate * -2 is returned if we time out, -1 is returned if interrupted, and the 476*7c478bd9Sstevel@tonic-gate * character is returned otherwise. 477*7c478bd9Sstevel@tonic-gate */ 478*7c478bd9Sstevel@tonic-gate 479*7c478bd9Sstevel@tonic-gate #ifndef FIONREAD 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate /* 482*7c478bd9Sstevel@tonic-gate * Traditional implementation. The best resolution we have is 1 second, 483*7c478bd9Sstevel@tonic-gate * so we set a 1 second alarm and try to read. If we fail for 1 second, 484*7c478bd9Sstevel@tonic-gate * we assume there is no key waiting. Problem here is that 1 second is 485*7c478bd9Sstevel@tonic-gate * too long; people can type faster than this. 486*7c478bd9Sstevel@tonic-gate * 487*7c478bd9Sstevel@tonic-gate * Another possible implementation of changing VMIN/VTIME before and 488*7c478bd9Sstevel@tonic-gate * after each read does not work because the tty driver's timeout 489*7c478bd9Sstevel@tonic-gate * mechanism is too unreliable when the timeouts are changed too quickly. 490*7c478bd9Sstevel@tonic-gate */ 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate static char sig_caught; 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate static 495*7c478bd9Sstevel@tonic-gate #ifdef SIGPOLL /* Vr3 and beyond */ 496*7c478bd9Sstevel@tonic-gate void 497*7c478bd9Sstevel@tonic-gate #endif /* SIGPOLL */ 498*7c478bd9Sstevel@tonic-gate /* The following line causes a lint warning for "dummy" which is not used. */ 499*7c478bd9Sstevel@tonic-gate _catch_alarm(int dummy) 500*7c478bd9Sstevel@tonic-gate { 501*7c478bd9Sstevel@tonic-gate sig_caught = 1; 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate static int 505*7c478bd9Sstevel@tonic-gate _fpk(void) 506*7c478bd9Sstevel@tonic-gate { 507*7c478bd9Sstevel@tonic-gate unsigned char c; 508*7c478bd9Sstevel@tonic-gate int infd = cur_term->_inputfd; 509*7c478bd9Sstevel@tonic-gate ssize_t rc; 510*7c478bd9Sstevel@tonic-gate #ifdef SIGPOLL /* Vr3 and beyond */ 511*7c478bd9Sstevel@tonic-gate void (*oldsig)(int); 512*7c478bd9Sstevel@tonic-gate #else /* SIGPOLL */ 513*7c478bd9Sstevel@tonic-gate int (*oldsig)(int); 514*7c478bd9Sstevel@tonic-gate #endif /* SIGPOLL */ 515*7c478bd9Sstevel@tonic-gate unsigned int oldalarm, alarm(unsigned); 516*7c478bd9Sstevel@tonic-gate 517*7c478bd9Sstevel@tonic-gate /* turn off any user alarms and set our own */ 518*7c478bd9Sstevel@tonic-gate oldalarm = alarm(0); 519*7c478bd9Sstevel@tonic-gate sig_caught = 0; 520*7c478bd9Sstevel@tonic-gate oldsig = signal(SIGALRM, _catch_alarm); 521*7c478bd9Sstevel@tonic-gate (void) alarm(1); 522*7c478bd9Sstevel@tonic-gate rc = read(cur_term->_inputfd, (char *)&c, 1); 523*7c478bd9Sstevel@tonic-gate (void) alarm(0); 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate * This code is to take care of the possibility of 527*7c478bd9Sstevel@tonic-gate * the process getting swapped out in the middle of 528*7c478bd9Sstevel@tonic-gate * read() call above. The interrupt will cause the 529*7c478bd9Sstevel@tonic-gate * read() call to retur, even if a character is really 530*7c478bd9Sstevel@tonic-gate * on the clist. So we do a non-blocking read() to make 531*7c478bd9Sstevel@tonic-gate * sure that there really isn't a character there. 532*7c478bd9Sstevel@tonic-gate */ 533*7c478bd9Sstevel@tonic-gate 534*7c478bd9Sstevel@tonic-gate if (sig_caught && rc != 1) 535*7c478bd9Sstevel@tonic-gate if (cur_term->_check_fd != -1) 536*7c478bd9Sstevel@tonic-gate rc = read(cur_term->_check_fd, (char *)&c, 1); 537*7c478bd9Sstevel@tonic-gate else { 538*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 539*7c478bd9Sstevel@tonic-gate int fcflags = fcntl(infd, F_GETFL, 0); 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate (void) fcntl(infd, F_SETFL, fcflags | O_NDELAY); 542*7c478bd9Sstevel@tonic-gate rc = read(infd, (char *)&c, 1); 543*7c478bd9Sstevel@tonic-gate (void) fcntl(infd, F_SETFL, fcflags); 544*7c478bd9Sstevel@tonic-gate } 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate /* restore the user alarms */ 547*7c478bd9Sstevel@tonic-gate (void) signal(SIGALRM, oldsig); 548*7c478bd9Sstevel@tonic-gate if (sig_caught && oldalarm > 1) 549*7c478bd9Sstevel@tonic-gate oldalarm--; 550*7c478bd9Sstevel@tonic-gate (void) alarm(oldalarm); 551*7c478bd9Sstevel@tonic-gate if (rc == 1) /* got a character */ 552*7c478bd9Sstevel@tonic-gate return (c); 553*7c478bd9Sstevel@tonic-gate else 554*7c478bd9Sstevel@tonic-gate if (sig_caught) /* timed out */ 555*7c478bd9Sstevel@tonic-gate return (-2); 556*7c478bd9Sstevel@tonic-gate else /* EOF or got interrupted */ 557*7c478bd9Sstevel@tonic-gate return (-1); 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate #else /* FIONREAD */ 560*7c478bd9Sstevel@tonic-gate /* 561*7c478bd9Sstevel@tonic-gate * If we have the select system call, we can do much better than the 562*7c478bd9Sstevel@tonic-gate * traditional method. Even if we don't have the real 4.2BSD select, we 563*7c478bd9Sstevel@tonic-gate * can emulate it with napms and FIONREAD. napms might be done with only 564*7c478bd9Sstevel@tonic-gate * 1 second resolution, but this is no worse than what we have in the 565*7c478bd9Sstevel@tonic-gate * traditional implementation. 566*7c478bd9Sstevel@tonic-gate */ 567*7c478bd9Sstevel@tonic-gate static 568*7c478bd9Sstevel@tonic-gate _fpk() 569*7c478bd9Sstevel@tonic-gate { 570*7c478bd9Sstevel@tonic-gate int infd, rc; 571*7c478bd9Sstevel@tonic-gate int *outfd, *exfd; 572*7c478bd9Sstevel@tonic-gate unsigned char c; 573*7c478bd9Sstevel@tonic-gate struct timeval t; 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate infd = 1 << cur_term->_inputfd; 576*7c478bd9Sstevel@tonic-gate outfd = exfd = (int *)NULL; 577*7c478bd9Sstevel@tonic-gate t.tv_sec = 0; 578*7c478bd9Sstevel@tonic-gate t.tv_usec = 100000; /* 100 milliseconds */ 579*7c478bd9Sstevel@tonic-gate rc = select(20, &infd, outfd, exfd, &t); 580*7c478bd9Sstevel@tonic-gate if (rc < 0) 581*7c478bd9Sstevel@tonic-gate return (-2); 582*7c478bd9Sstevel@tonic-gate rc = read(fileno(f), &c, 1); 583*7c478bd9Sstevel@tonic-gate return (rc == 1 ? c : -1); 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate #endif /* FIONREAD */ 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate /* 588*7c478bd9Sstevel@tonic-gate * Plain peekchar function. Nothing fancy. This is just like _fpk 589*7c478bd9Sstevel@tonic-gate * but will wait forever rather than time out. 590*7c478bd9Sstevel@tonic-gate */ 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate static int 593*7c478bd9Sstevel@tonic-gate _pk(void) 594*7c478bd9Sstevel@tonic-gate { 595*7c478bd9Sstevel@tonic-gate unsigned char c; 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate return ((read(cur_term->_inputfd, (char *)&c, 1) == 1) ? c : ERR); 598*7c478bd9Sstevel@tonic-gate } 599*7c478bd9Sstevel@tonic-gate 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate /* 602*7c478bd9Sstevel@tonic-gate * SS-mouse: check if this mouse button event should map into 603*7c478bd9Sstevel@tonic-gate * function key 604*7c478bd9Sstevel@tonic-gate */ 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate static void 608*7c478bd9Sstevel@tonic-gate _map_button(chtype *inp) 609*7c478bd9Sstevel@tonic-gate { 610*7c478bd9Sstevel@tonic-gate SLK_MAP *slk = SP->slk; 611*7c478bd9Sstevel@tonic-gate int num = slk->_num; 612*7c478bd9Sstevel@tonic-gate int len = slk->_len; 613*7c478bd9Sstevel@tonic-gate int i; 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate /* first determine if this mouse button event should be */ 616*7c478bd9Sstevel@tonic-gate /* mapped into function key */ 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate if (!(SP->_map_mbe_to_key & 619*7c478bd9Sstevel@tonic-gate ((BUTTON_CHANGED(3) << (10 + BUTTON_STATUS(3))) | 620*7c478bd9Sstevel@tonic-gate (BUTTON_CHANGED(2) << (5 + BUTTON_STATUS(2))) | 621*7c478bd9Sstevel@tonic-gate (BUTTON_CHANGED(1) << BUTTON_STATUS(1))))) 622*7c478bd9Sstevel@tonic-gate return; 623*7c478bd9Sstevel@tonic-gate 624*7c478bd9Sstevel@tonic-gate for (i = 0; i < num; i++) { 625*7c478bd9Sstevel@tonic-gate if (MOUSE_X_POS < slk->_labx[i]) 626*7c478bd9Sstevel@tonic-gate break; 627*7c478bd9Sstevel@tonic-gate if (MOUSE_X_POS > slk->_labx[i] + len) 628*7c478bd9Sstevel@tonic-gate continue; 629*7c478bd9Sstevel@tonic-gate *inp = KEY_F(1) + i; 630*7c478bd9Sstevel@tonic-gate break; 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate } 633