input.c

Go to the documentation of this file.
00001 /*      $OpenBSD: input.c,v 1.12 2005/04/13 02:33:08 deraadt Exp $      */
00002 /*    $NetBSD: input.c,v 1.3 1996/02/06 22:47:33 jtc Exp $    */
00003 
00004 /*-
00005  * Copyright (c) 1992, 1993
00006  *      The Regents of the University of California.  All rights reserved.
00007  *
00008  * This code is derived from software contributed to Berkeley by
00009  * Chris Torek and Darren F. Provine.
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  * 1. Redistributions of source code must retain the above copyright
00015  *    notice, this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright
00017  *    notice, this list of conditions and the following disclaimer in the
00018  *    documentation and/or other materials provided with the distribution.
00019  * 3. Neither the name of the University nor the names of its contributors
00020  *    may be used to endorse or promote products derived from this software
00021  *    without specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  *
00035  *      @(#)input.c     8.1 (Berkeley) 5/31/93
00036  */
00037 
00044 /*
00045  * Tetris input.
00046  */
00047 
00048 #include <sys/types.h>
00049 #include <sys/time.h>
00050 #include <stdio.h>
00051 
00052 #include <errno.h>
00053 #include <unistd.h>
00054 #include <str.h>
00055 
00056 #include "input.h"
00057 #include "tetris.h"
00058 
00059 #include <async.h>
00060 #include <vfs/vfs.h>
00061 #include <io/console.h>
00062 #include <ipc/console.h>
00063 
00064 /* return true iff the given timeval is positive */
00065 #define TV_POS(tv) \
00066         ((tv)->tv_sec > 0 || ((tv)->tv_sec == 0 && (tv)->tv_usec > 0))
00067 
00068 /* subtract timeval `sub' from `res' */
00069 #define TV_SUB(res, sub) \
00070         (res)->tv_sec -= (sub)->tv_sec; \
00071         (res)->tv_usec -= (sub)->tv_usec; \
00072         if ((res)->tv_usec < 0) { \
00073                 (res)->tv_usec += 1000000; \
00074                 (res)->tv_sec--; \
00075         }
00076 
00077 /* We will use a hack here - if lastchar is non-zero, it is
00078  * the last character read. We will somehow simulate the select
00079  * semantics.
00080  */
00081 static aid_t getchar_inprog = 0;
00082 static char lastchar = '\0';
00083 
00084 /*
00085  * Do a `read wait': select for reading from stdin, with timeout *tvp.
00086  * On return, modify *tvp to reflect the amount of time spent waiting.
00087  * It will be positive only if input appeared before the time ran out;
00088  * otherwise it will be zero or perhaps negative.
00089  *
00090  * If tvp is nil, wait forever, but return if select is interrupted.
00091  *
00092  * Return 0 => no input, 1 => can read() from stdin
00093  *
00094  */
00095 int rwait(struct timeval *tvp)
00096 {
00097         struct timeval starttv, endtv, *s;
00098         static ipc_call_t charcall;
00099         sysarg_t rc;
00100         
00101         /*
00102          * Someday, select() will do this for us.
00103          * Just in case that day is now, and no one has
00104          * changed this, we use a temporary.
00105          */
00106         if (tvp) {
00107                 (void) gettimeofday(&starttv, NULL);
00108                 endtv = *tvp;
00109                 s = &endtv;
00110         } else
00111                 s = NULL;
00112         
00113         if (!lastchar) {
00114 again:
00115                 if (!getchar_inprog) {
00116                         getchar_inprog = async_send_0(fphone(stdin),
00117                             CONSOLE_GET_EVENT, &charcall);
00118                 }
00119                 
00120                 if (!s)
00121                         async_wait_for(getchar_inprog, &rc);
00122                 else if (async_wait_timeout(getchar_inprog, &rc, s->tv_usec) == ETIMEOUT) {
00123                         tvp->tv_sec = 0;
00124                         tvp->tv_usec = 0;
00125                         return (0);
00126                 }
00127                 
00128                 getchar_inprog = 0;
00129                 if (rc)
00130                         stop("end of file, help");
00131                 
00132                 if (IPC_GET_ARG1(charcall) == KEY_RELEASE)
00133                         goto again;
00134                 
00135                 lastchar = IPC_GET_ARG4(charcall);
00136         }
00137         
00138         if (tvp) {
00139                 /* since there is input, we may not have timed out */
00140                 (void) gettimeofday(&endtv, NULL);
00141                 TV_SUB(&endtv, &starttv);
00142                 TV_SUB(tvp, &endtv);  /* adjust *tvp by elapsed time */
00143         }
00144         
00145         return 1;
00146 }
00147 
00148 /*
00149  * `sleep' for the current turn time (using select).
00150  * Eat any input that might be available.
00151  */
00152 void tsleep(void)
00153 {
00154         struct timeval tv;
00155         
00156         tv.tv_sec = 0;
00157         tv.tv_usec = fallrate;
00158         while (TV_POS(&tv))
00159                 if (rwait(&tv)) {
00160                         lastchar = '\0';
00161                 } else
00162                         break;
00163 }
00164 
00165 /*
00166  * getchar with timeout.
00167  */
00168 int tgetchar(void)
00169 {
00170         static struct timeval timeleft;
00171         char c;
00172         
00173         /*
00174          * Reset timeleft to fallrate whenever it is not positive.
00175          * In any case, wait to see if there is any input.  If so,
00176          * take it, and update timeleft so that the next call to
00177          * tgetchar() will not wait as long.  If there is no input,
00178          * make timeleft zero or negative, and return -1.
00179          *
00180          * Most of the hard work is done by rwait().
00181          */
00182         if (!TV_POS(&timeleft)) {
00183                 faster();  /* go faster */
00184                 timeleft.tv_sec = 0;
00185                 timeleft.tv_usec = fallrate;
00186         }
00187         
00188         if (!rwait(&timeleft))
00189                 return -1;
00190         
00191         c = lastchar;
00192         lastchar = '\0';
00193         return ((int) (unsigned char) c);
00194 }
00195 

Generated on Thu Jun 2 07:45:41 2011 for HelenOS/USB by  doxygen 1.4.7