1 /* Public Domain Curses */
2 
3 #include <curspriv.h>
4 
5 RCSID("$Id: getch.c,v 1.72 2008/07/13 16:08:18 wmcbrine Exp $")
6 
7 /*man-start**************************************************************
8 
9   Name:                                                         getch
10 
11   Synopsis:
12         int getch(void);
13         int wgetch(WINDOW *win);
14         int mvgetch(int y, int x);
15         int mvwgetch(WINDOW *win, int y, int x);
16         int ungetch(int ch);
17         int flushinp(void);
18 
19         int get_wch(wint_t *wch);
20         int wget_wch(WINDOW *win, wint_t *wch);
21         int mvget_wch(int y, int x, wint_t *wch);
22         int mvwget_wch(WINDOW *win, int y, int x, wint_t *wch);
23         int unget_wch(const wchar_t wch);
24 
25         unsigned long PDC_get_key_modifiers(void);
26         int PDC_save_key_modifiers(bool flag);
27         int PDC_return_key_modifiers(bool flag);
28 
29   Description:
30         With the getch(), wgetch(), mvgetch(), and mvwgetch() functions,
31         a character is read from the terminal associated with the window.
32         In nodelay mode, if there is no input waiting, the value ERR is
33         returned. In delay mode, the program will hang until the system
34         passes text through to the program. Depending on the setting of
35         cbreak(), this will be after one character or after the first
36         newline.  Unless noecho() has been set, the character will also
37         be echoed into the designated window.
38 
39         If keypad() is TRUE, and a function key is pressed, the token for
40         that function key will be returned instead of the raw characters.
41         Possible function keys are defined in <curses.h> with integers
42         beginning with 0401, whose names begin with KEY_.
43 
44         If nodelay(win, TRUE) has been called on the window and no input
45         is waiting, the value ERR is returned.
46 
47         ungetch() places ch back onto the input queue to be returned by
48         the next call to wgetch().
49 
50         flushinp() throws away any type-ahead that has been typed by the
51         user and has not yet been read by the program.
52 
53         PDC_get_key_modifiers() returns the keyboard modifiers (shift,
54         control, alt, numlock) effective at the time of the last getch()
55         call, if PDC_save_key_modifiers(TRUE) has been called before the
56         getch(). Use the macros PDC_KEY_MODIFIER_* to determine which
57         modifier(s) were set. PDC_return_key_modifiers() tells getch()
58         to return modifier keys pressed alone as keystrokes (KEY_ALT_L,
59         etc.). These may not work on all platforms.
60 
61         NOTE: getch() and ungetch() are implemented as macros, to avoid
62         conflict with many DOS compiler's runtime libraries.
63 
64   Return Value:
65         These functions return ERR or the value of the character, meta
66         character or function key token.
67 
68   Portability                                X/Open    BSD    SYS V
69         getch                                   Y       Y       Y
70         wgetch                                  Y       Y       Y
71         mvgetch                                 Y       Y       Y
72         mvwgetch                                Y       Y       Y
73         ungetch                                 Y       Y       Y
74         flushinp                                Y       Y       Y
75         get_wch                                 Y
76         wget_wch                                Y
77         mvget_wch                               Y
78         mvwget_wch                              Y
79         unget_wch                               Y
80         PDC_get_key_modifiers                   -       -       -
81 
82 **man-end****************************************************************/
83 
84 #define _INBUFSIZ   512 /* size of terminal input buffer */
85 #define NUNGETCH    256 /* max # chars to ungetch() */
86 
87 static int c_pindex = 0;    /* putter index */
88 static int c_gindex = 1;    /* getter index */
89 static int c_ungind = 0;    /* ungetch() push index */
90 static int c_ungch[NUNGETCH];   /* array of ungotten chars */
91 
_mouse_key(WINDOW * win)92 static int _mouse_key(WINDOW *win)
93 {
94     int i, key = KEY_MOUSE;
95     unsigned long mbe = SP->_trap_mbe;
96 
97     /* Filter unwanted mouse events */
98 
99     for (i = 0; i < 3; i++)
100     {
101         if (pdc_mouse_status.changes & (1 << i))
102         {
103             int shf = i * 5;
104             short button = pdc_mouse_status.button[i] & BUTTON_ACTION_MASK;
105 
106             if (   (!(mbe & (BUTTON1_PRESSED << shf)) &&
107                     (button == BUTTON_PRESSED))
108 
109                 || (!(mbe & (BUTTON1_CLICKED << shf)) &&
110                     (button == BUTTON_CLICKED))
111 
112                 || (!(mbe & (BUTTON1_DOUBLE_CLICKED << shf)) &&
113                     (button == BUTTON_DOUBLE_CLICKED))
114 
115                 || (!(mbe & (BUTTON1_MOVED << shf)) &&
116                     (button == BUTTON_MOVED))
117 
118                 || (!(mbe & (BUTTON1_RELEASED << shf)) &&
119                     (button == BUTTON_RELEASED))
120             )
121                 pdc_mouse_status.changes ^= (1 << i);
122         }
123     }
124 
125     if (pdc_mouse_status.changes & PDC_MOUSE_MOVED)
126     {
127         if (!(mbe & (BUTTON1_MOVED|BUTTON2_MOVED|BUTTON3_MOVED)))
128             pdc_mouse_status.changes ^= PDC_MOUSE_MOVED;
129     }
130 
131     if (pdc_mouse_status.changes &
132         (PDC_MOUSE_WHEEL_UP|PDC_MOUSE_WHEEL_DOWN))
133     {
134         if (!(mbe & MOUSE_WHEEL_SCROLL))
135             pdc_mouse_status.changes &=
136                 ~(PDC_MOUSE_WHEEL_UP|PDC_MOUSE_WHEEL_DOWN);
137     }
138 
139     if (!pdc_mouse_status.changes)
140         return -1;
141 
142     /* Check for click in slk area */
143 
144     i = PDC_mouse_in_slk(pdc_mouse_status.y, pdc_mouse_status.x);
145 
146     if (i)
147     {
148         if (pdc_mouse_status.button[0] & (BUTTON_PRESSED|BUTTON_CLICKED))
149             key = KEY_F(i);
150         else
151             key = -1;
152     }
153 
154     return key;
155 }
156 
wgetch(WINDOW * win)157 int wgetch(WINDOW *win)
158 {
159     static int buffer[_INBUFSIZ];   /* character buffer */
160     int key, waitcount;
161 
162     PDC_LOG(("wgetch() - called\n"));
163 
164     if (!win)
165         return ERR;
166 
167     waitcount = 0;
168 
169      /* set the number of 1/20th second napms() calls */
170 
171     if (SP->delaytenths)
172         waitcount = 2 * SP->delaytenths;
173     else
174         if (win->_delayms)
175         {
176             /* Can't really do millisecond intervals, so delay in
177                1/20ths of a second (50ms) */
178 
179             waitcount = win->_delayms / 50;
180             if (!waitcount)
181                 waitcount = 1;
182         }
183 
184     /* refresh window when wgetch is called if there have been changes
185        to it and it is not a pad */
186 
187     if (!(win->_flags & _PAD) && ((!win->_leaveit &&
188          (win->_begx + win->_curx != SP->curscol ||
189           win->_begy + win->_cury != SP->cursrow)) || is_wintouched(win)))
190         wrefresh(win);
191 
192     /* if ungotten char exists, remove and return it */
193 
194     if (c_ungind)
195         return c_ungch[--c_ungind];
196 
197     /* if normal and data in buffer */
198 
199     if ((!SP->raw_inp && !SP->cbreak) && (c_gindex < c_pindex))
200         return buffer[c_gindex++];
201 
202     /* prepare to buffer data */
203 
204     c_pindex = 0;
205     c_gindex = 0;
206 
207     /* to get here, no keys are buffered. go and get one. */
208 
209     for (;;)            /* loop for any buffering */
210     {
211         /* is there a keystroke ready? */
212 
213         if (!PDC_check_key())
214         {
215             /* if not, handle timeout() and halfdelay() */
216 
217             if (SP->delaytenths || win->_delayms)
218             {
219                 if (!waitcount)
220                     return ERR;
221 
222                 waitcount--;
223             }
224             else
225                 if (win->_nodelay)
226                     return ERR;
227 
228             napms(50);  /* sleep for 1/20th second */
229             continue;   /* then check again */
230         }
231 
232         /* if there is, fetch it */
233 
234         key = PDC_get_key();
235 
236         if (SP->key_code)
237         {
238             /* filter special keys if not in keypad mode */
239 
240             if (!win->_use_keypad)
241                 key = -1;
242 
243             /* filter mouse events; translate mouse clicks in the slk
244                area to function keys */
245 
246             else if (key == KEY_MOUSE)
247                 key = _mouse_key(win);
248         }
249 
250         /* unwanted key? loop back */
251 
252         if (key == -1)
253             continue;
254 
255         /* translate CR */
256 
257         if (key == '\r' && SP->autocr && !SP->raw_inp)
258             key = '\n';
259 
260         /* if echo is enabled */
261 
262         if (SP->echo && !SP->key_code)
263         {
264             waddch(win, key);
265             wrefresh(win);
266         }
267 
268         /* if no buffering */
269 
270         if (SP->raw_inp || SP->cbreak)
271             return key;
272 
273         /* if no overflow, put data in buffer */
274 
275         if (key == '\b')
276         {
277             if (c_pindex > c_gindex)
278                 c_pindex--;
279         }
280         else
281             if (c_pindex < _INBUFSIZ - 2)
282                 buffer[c_pindex++] = key;
283 
284         /* if we got a line */
285 
286         if (key == '\n' || key == '\r')
287             return buffer[c_gindex++];
288     }
289 }
290 
mvgetch(int y,int x)291 int mvgetch(int y, int x)
292 {
293     PDC_LOG(("mvgetch() - called\n"));
294 
295     if (move(y, x) == ERR)
296         return ERR;
297 
298     return wgetch(stdscr);
299 }
300 
mvwgetch(WINDOW * win,int y,int x)301 int mvwgetch(WINDOW *win, int y, int x)
302 {
303     PDC_LOG(("mvwgetch() - called\n"));
304 
305     if (wmove(win, y, x) == ERR)
306         return ERR;
307 
308     return wgetch(win);
309 }
310 
PDC_ungetch(int ch)311 int PDC_ungetch(int ch)
312 {
313     PDC_LOG(("ungetch() - called\n"));
314 
315     if (c_ungind >= NUNGETCH)   /* pushback stack full */
316         return ERR;
317 
318     c_ungch[c_ungind++] = ch;
319 
320     return OK;
321 }
322 
flushinp(void)323 int flushinp(void)
324 {
325     PDC_LOG(("flushinp() - called\n"));
326 
327     PDC_flushinp();
328 
329     c_gindex = 1;           /* set indices to kill buffer */
330     c_pindex = 0;
331     c_ungind = 0;           /* clear c_ungch array */
332 
333     return OK;
334 }
335 
PDC_get_key_modifiers(void)336 unsigned long PDC_get_key_modifiers(void)
337 {
338     PDC_LOG(("PDC_get_key_modifiers() - called\n"));
339 
340     return pdc_key_modifiers;
341 }
342 
PDC_save_key_modifiers(bool flag)343 int PDC_save_key_modifiers(bool flag)
344 {
345     PDC_LOG(("PDC_save_key_modifiers() - called\n"));
346 
347     SP->save_key_modifiers = flag;
348     return OK;
349 }
350 
PDC_return_key_modifiers(bool flag)351 int PDC_return_key_modifiers(bool flag)
352 {
353     PDC_LOG(("PDC_return_key_modifiers() - called\n"));
354 
355     SP->return_key_modifiers = flag;
356     return PDC_modifiers_set();
357 }
358 
359 #ifdef PDC_WIDE
wget_wch(WINDOW * win,wint_t * wch)360 int wget_wch(WINDOW *win, wint_t *wch)
361 {
362     int key;
363 
364     PDC_LOG(("wget_wch() - called\n"));
365 
366     if (!wch)
367         return ERR;
368 
369     key = wgetch(win);
370 
371     if (key == ERR)
372         return ERR;
373 
374     *wch = key;
375 
376     return SP->key_code ? KEY_CODE_YES : OK;
377 }
378 
get_wch(wint_t * wch)379 int get_wch(wint_t *wch)
380 {
381     PDC_LOG(("get_wch() - called\n"));
382 
383     return wget_wch(stdscr, wch);
384 }
385 
mvget_wch(int y,int x,wint_t * wch)386 int mvget_wch(int y, int x, wint_t *wch)
387 {
388     PDC_LOG(("mvget_wch() - called\n"));
389 
390     if (move(y, x) == ERR)
391         return ERR;
392 
393     return wget_wch(stdscr, wch);
394 }
395 
mvwget_wch(WINDOW * win,int y,int x,wint_t * wch)396 int mvwget_wch(WINDOW *win, int y, int x, wint_t *wch)
397 {
398     PDC_LOG(("mvwget_wch() - called\n"));
399 
400     if (wmove(win, y, x) == ERR)
401         return ERR;
402 
403     return wget_wch(win, wch);
404 }
405 
unget_wch(const wchar_t wch)406 int unget_wch(const wchar_t wch)
407 {
408     return PDC_ungetch(wch);
409 }
410 #endif
411