]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libncurses/lib_getch.c
Make bdev userland access work like cdev userland access unless
[FreeBSD/FreeBSD.git] / lib / libncurses / lib_getch.c
1
2 /* This work is copyrighted. See COPYRIGHT.OLD & COPYRIGHT.NEW for   *
3 *  details. If they are missing then this copy is in violation of    *
4 *  the copyright conditions.                                        */
5
6 /*
7 **      lib_getch.c
8 **
9 **      The routine getch().
10 **
11 */
12
13 #include <sys/types.h>
14 #include <string.h>
15 #include <signal.h>
16 #include <errno.h>
17 #if defined(BRAINDEAD)
18 extern int errno;
19 #endif
20 #include "curses.priv.h"
21
22 #define head    SP->_fifohead
23 #define tail    SP->_fifotail
24 #define peek    SP->_fifopeek
25
26 #define h_inc() { head == FIFO_SIZE-1 ? head = 0 : head++; if (head == tail) head = -1, tail = 0;}
27 #define h_dec() { head == 0 ?  head = FIFO_SIZE-1 : head--; if (head == tail) tail = -1;}
28 #define t_inc() { tail == FIFO_SIZE-1 ? tail = 0 : tail++; if (tail == head) tail = -1;}
29 #define p_inc() { peek == FIFO_SIZE-1 ? peek = 0 : peek++;}
30
31 static int fifo_peek()
32 {
33         T(("peeking at %d", peek+1));
34         return SP->_fifo[++peek];
35 }
36
37 static inline void fifo_dump()
38 {
39 int i;
40         T(("head = %d, tail = %d, peek = %d", head, tail, peek));
41         for (i = 0; i < 10; i++)
42                 T(("char %d = %d (%c)", i, SP->_fifo[i], (unsigned char)SP->_fifo[i]));
43 }
44
45 static inline int fifo_pull()
46 {
47 int ch;
48         ch = SP->_fifo[head];
49         T(("pulling %d from %d", ch, head));
50
51         h_inc();
52         fifo_dump();
53         return ch;
54 }
55
56 int ungetch(int ch)
57 {
58         if (tail == -1)
59                 return ERR;
60         if (head == -1) {
61                 head = 0;
62                 t_inc()
63         } else
64                 h_dec();
65
66         SP->_fifo[head] = ch;
67         T(("ungetch ok"));
68         fifo_dump();
69         return OK;
70 }
71
72 static inline int fifo_push()
73 {
74 int n;
75 unsigned char ch;
76
77         if (tail == -1) return ERR;
78 again:
79         n = read(fileno(SP->_ifp), &ch, 1);
80         if (n == -1 && errno == EINTR)
81                 goto again;
82         T(("read %d characters", n));
83         SP->_fifo[tail] = ch;
84         if (head == -1) head = tail;
85         t_inc();
86         T(("pushed %d at %d", ch, tail));
87         fifo_dump();
88         return ch;
89 }
90
91 static inline void fifo_clear()
92 {
93 int i;
94         for (i = 0; i < FIFO_SIZE; i++)
95                 SP->_fifo[i] = 0;
96         head = -1; tail = peek = 0;
97 }
98
99 static int kgetch(WINDOW *);
100
101 int
102 wgetch(WINDOW *win)
103 {
104 bool    setHere = FALSE;        /* cbreak mode was set here */
105 int     ch;
106
107         T(("wgetch(%x) called", win));
108
109         /* this should be eliminated */
110         if (! win->_scroll  &&  (SP->_echo) &&  (win->_flags & _FULLWIN)
111            &&  win->_curx == win->_maxx &&  win->_cury == win->_maxy)
112                 return(ERR);
113
114         if ((is_wintouched(win) || (win->_flags & _HASMOVED)) &&
115             !(win->_flags & _ISPAD))
116                 wrefresh(win);
117
118         if (SP->_echo  &&  ! (SP->_raw  ||  SP->_cbreak)) {
119                 cbreak();
120                 setHere = TRUE;
121         }
122
123         if (win->_delay >= 0 || SP->_cbreak > 1) {
124         int delay;
125
126                 T(("timed delay in wgetch()"));
127                 if (SP->_cbreak > 1)
128                     delay = (SP->_cbreak-1) * 100;
129                 else
130                     delay = win->_delay;
131
132                 T(("delay is %d microseconds", delay));
133
134                 if (head == -1) /* fifo is empty */
135                         if (timed_wait(fileno(SP->_ifp), delay, NULL) == 0)
136                                 return ERR;
137                 /* else go on to read data available */
138         }
139
140         if (win->_use_keypad)
141                 ch = kgetch(win);
142         else {
143                 if (head == -1)
144                         fifo_push();
145                 ch = fifo_pull();
146         }
147
148         /* This should be eliminated */
149         /* handle 8-bit input */
150         if (ch & 0x80)
151                 if (!win->_use_meta)
152                         ch &= 0x7f;
153
154         /* there must be a simpler way of doing this */
155         if (!(win->_flags & _ISPAD) &&
156              SP->_echo  &&  ch < 0400) {   /* ch < 0400 => not a keypad key */
157                 mvwaddch(curscr, win->_begy + win->_cury,
158                          win->_begx + win->_curx, ch | win->_attrs);
159                 waddch(win, ch | win->_attrs);
160         }
161         if (setHere)
162             nocbreak();
163
164         T(("wgetch returning : '%c', '0x%x'", ch, ch));
165
166         return(ch);
167 }
168
169
170 /*
171 **      int
172 **      kgetch()
173 **
174 **      Get an input character, but take care of keypad sequences, returning
175 **      an appropriate code when one matches the input.  After each character
176 **      is received, set a one-second alarm call.  If no more of the sequence
177 **      is received by the time the alarm goes off, pass through the sequence
178 **      gotten so far.
179 **
180 */
181
182 static int
183 kgetch(WINDOW *win)
184 {
185 struct try  *ptr;
186 int ch = 0;
187 int timeleft = 1000;
188
189     T(("kgetch(%x) called", win));
190
191     ptr = SP->_keytry;
192
193         if (head == -1)  {
194                 ch = fifo_push();
195                 peek = 0;
196         while (ptr != NULL) {
197                         T(("ch = %d", ch));
198                         while ((ptr != NULL) && (ptr->ch != (unsigned char)ch))
199                             ptr = ptr->sibling;
200
201                         if (ptr != NULL)
202                     if (ptr->value != 0) {      /* sequence terminated */
203                         T(("end of sequence"));
204                         fifo_clear();
205                                 return(ptr->value);
206                     } else {                    /* go back for another character */
207                                 ptr = ptr->child;
208                                 T(("going back for more"));
209                     } else
210                                 break;
211
212                     T(("waiting for rest of sequence"));
213                         if (timed_wait(fileno(SP->_ifp), timeleft, &timeleft) < 1) {
214                                 T(("ran out of time"));
215                                 return(fifo_pull());
216                         } else {
217                                 T(("got more!"));
218                                 fifo_push();
219                                 ch = fifo_peek();
220                         }
221                 }
222     }
223     return(fifo_pull());
224 }