Windows: fix keystroke delay in waitkey
[openafs.git] / src / lwp / waitkey.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * LWP_WaitForKeystroke - wait indefinitely or for a specified number of
12  * seconds for keyboard input.
13  *
14  * If seconds < 0, LWP_WaitForKeystroke will wait indefinitely.
15  * If seconds == 0, LWP_WaitForKeystroke will just determine if data is now
16  *      present.
17  * Otherwise, wait "seconds" for data.
18  *
19  * Return 1 if data available.
20  */
21
22 #include <afsconfig.h>
23 #include <afs/param.h>
24
25
26 #include <stdio.h>
27 #ifdef HAVE_STDIO_EXT_H
28 #include <stdio_ext.h>
29 #endif
30 #include <sys/types.h>
31 #ifdef AFS_NT40_ENV
32 #include <time.h>
33 #include <conio.h>
34 #include <assert.h>
35 #else
36 #include <sys/time.h>
37 #include <unistd.h>
38 #endif
39 #include <string.h>
40 #include "lwp.h"
41
42 #define LWP_KEYSTROKE_DELAY   250       /* 250ms. Must be < 1000 */
43 #define LWP_MAXLINELEN  256
44
45 #ifdef AFS_NT40_ENV
46 /* LWP_WaitForKeystroke : Wait until a key has been struck or time (secconds)
47  * runs out and return to caller. The NT version of this function will return
48  * immediately after a key has been pressed (doesn't wait for cr).
49  * Input:
50  *   seconds: wait for <seconds> seconds before returning. If seconds < 0,
51  *            wait infinitely.
52  * Return Value:
53  *    1:  Keyboard input available
54  *    0:  seconds elapsed. Timeout.
55  */
56 int
57 LWP_WaitForKeystroke(int seconds)
58 {
59     time_t startTime, nowTime;
60     double timeleft = 1;
61 #ifndef AFS_PTHREAD_ENV
62     struct timeval twait;
63
64     twait.tv_sec = 0;
65     twait.tv_usec = LWP_KEYSTROKE_DELAY;
66 #endif
67
68     time(&startTime);
69
70     if (seconds >= 0)
71         timeleft = seconds;
72
73     do {
74         /* check if we have a keystroke */
75         if (_kbhit())
76             return 1;
77
78         if (timeleft == 0)
79             break;
80
81         /* sleep for  LWP_KEYSTROKE_DELAY ms and let other
82          * process run some*/
83 #ifdef AFS_PTHREAD_ENV
84         Sleep(LWP_KEYSTROKE_DELAY);
85 #else
86         IOMGR_Select(0, 0, 0, 0, &twait);
87 #endif
88         if (seconds > 0) {      /* we only worry about elapsed time if
89                                  * not looping forever (seconds < 0) */
90             /* now check elapsed time */
91             time(&nowTime);
92             timeleft = seconds - difftime(nowTime, startTime);
93         }
94     }
95     while (timeleft > 0);
96
97     return 0;
98 }
99
100 /* LWP_GetLine() - Waits indefinitely until a newline has been typed
101  * and then returns the line typed.
102  *
103  * This is trivial in unix, but requires some processing on NT.
104  *   we basically read all chars into a buffer until we hit a newline and
105  *   then return it to the user.
106  * Return Value:
107  *   n - a whole line has been read.(has n chars)
108  *   0 - buf not big enough.
109  *   -1 - line with only EOF
110  */
111
112 int
113 LWP_GetLine(char *linebuf, int len)
114 {
115     int cnt = 0;
116     int ch = 0;
117
118     fflush(stdin);
119     /* loop until a new line has been entered */
120     while (ch != '\r' && cnt < len - 1) {
121         LWP_WaitForKeystroke(-1);
122         ch = getch();
123
124         if ((ch == EOF) && (cnt == 0))
125             return -1;
126
127         if (ch == '\b') {       /* print and throw away a backspace */
128             if (!cnt)           /* if we are at the start of the line don't bspace */
129                 continue;
130             /* print a space to delete char and move cursor back */
131             printf("\b \b");
132             cnt--;
133         } else {
134             putchar(ch);
135             linebuf[cnt++] = ch;
136         }
137     }
138
139     if (ch == '\r') {           /* got a cr. translate to nl */
140         linebuf[cnt - 1] = '\n';
141         linebuf[cnt] = '\0';
142         putchar('\n');
143         return cnt;
144     } else {                    /* buffer too small */
145         linebuf[cnt] = '\0';
146         return 0;
147     }
148
149 }
150 #else
151 /* LWP_WaitForKeystroke(Unix) :Wait until a key has been struck or time (secconds)
152  * runs out and return to caller. The Unix version will actually wait until
153  * a <cr> has been entered before returning.
154  * Input:
155  *   seconds: wait for <seconds> seconds before returning. If seconds < 0,
156  *            wait infinitely.
157  * Return Value:
158  *    1:  Keyboard input available
159  *    0:  seconds elapsed. Timeout.
160  */
161 int
162 LWP_WaitForKeystroke(int seconds)
163 {
164     fd_set rdfds;
165     int code;
166     struct timeval twait;
167     struct timeval *tp = NULL;
168
169 #if defined(HAVE_STDIO_EXT_H)
170     if (__fbufsize(stdin) > 0)
171         return 1;
172 #elif defined(AFS_LINUX20_ENV)
173     if (stdin->_IO_read_ptr < stdin->_IO_read_end)
174         return 1;
175 #elif (defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)) && defined(AFS_DFBSD_ENV)
176     struct appx_sbuf {
177       unsigned char *_base;
178       int     _size;
179     };
180     struct APPX_FILE
181     {
182       struct __FILE_public    pub;
183       struct  appx_sbuf _bf;     /* the buffer (at least 1 byte, if !NULL) */
184     };
185     struct APPX_FILE *appx_stdin = (struct APPX_FILE *) stdin;
186     if (appx_stdin->_bf._size > 0)
187         return 1;
188 #elif defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
189     if (stdin->_bf._size > 0)
190         return 1;
191 #else
192     if (stdin->_cnt > 0)
193         return 1;
194 #endif
195
196     FD_ZERO(&rdfds);
197     FD_SET(fileno(stdin), &rdfds);
198
199     if (seconds >= 0) {
200         twait.tv_sec = seconds;
201         twait.tv_usec = 0;
202         tp = &twait;
203     }
204
205 #ifdef AFS_PTHREAD_ENV
206     code = select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
207 #else
208     code = IOMGR_Select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
209 #endif
210
211     return (code == 1) ? 1 : 0;
212 }
213
214 /* LWP_GetLine() - Waits indefinitely until a newline has been typed
215  * and then returns the line typed.
216  *
217  * This is trivial in unix, but requires some processing on NT.
218  *   we basically read all chars into a buffer until we hit a newline and
219  *   then return it to the user.
220  * Return Value:
221  *   n - a whole line has been read.(has n chars)
222  *   0 - buf not big enough.
223  *   -1 - line with only EOF
224  */
225
226 int
227 LWP_GetLine(char *linebuf, int len)
228 {
229     int linelen;
230     char *s;
231
232     LWP_WaitForKeystroke(-1);
233
234     s = fgets(linebuf, len, stdin);
235     if (s == NULL)
236         return -1;
237
238     linelen = strlen(linebuf);
239     if (linebuf[linelen - 1] != '\n')   /* buffer too small */
240         return 0;
241     else
242         return linelen;
243 }
244
245 #endif /* else NT40 */
246
247 /* LWP_GetResponseKey() - Waits for a specified period of time and
248  * returns a char when one has been typed by the user.
249  * Input:
250  *    seconds - how long to wait for a key press.
251  *    *key    - char entered by user
252  * Return Values:
253  *    0 - Time ran out before the user typed a key.
254  *    1 - Valid char is being returned.
255  */
256
257 int
258 LWP_GetResponseKey(int seconds, char *key)
259 {
260     int rc;
261
262     if (key == NULL)
263         return 0;               /* need space to store char */
264
265
266     fflush(stdin);              /* flush all existing data and start anew */
267
268
269     rc = LWP_WaitForKeystroke(seconds);
270     if (rc == 0) {              /* time ran out */
271         *key = 0;
272         return rc;
273     }
274
275     /* now read the char. */
276 #ifdef AFS_NT40_ENV
277     *key = getche();            /* get char and echo it to screen */
278 #else
279     *key = (char)getchar();
280 #endif
281
282     return rc;
283 }