Merge branch 'release-4.0'
[kiteware-cmake.git] / Utilities / cmpdcurses / pdcurses / getch.c
blob58a44c27eec02a568639c724f4e016acfe02179c
1 /* PDCurses */
3 #include <curspriv.h>
5 /*man-start**************************************************************
7 getch
8 -----
10 ### 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);
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);
25 unsigned long PDC_get_key_modifiers(void);
26 int PDC_return_key_modifiers(bool flag);
28 ### Description
30 With the getch(), wgetch(), mvgetch(), and mvwgetch() functions, a
31 character is read from the terminal associated with the window. In
32 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 be
37 echoed into the designated window.
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_.
44 If nodelay(win, TRUE) has been called on the window and no input is
45 waiting, the value ERR is returned.
47 ungetch() places ch back onto the input queue to be returned by the
48 next call to wgetch().
50 flushinp() throws away any type-ahead that has been typed by the user
51 and has not yet been read by the program.
53 wget_wch() is the wide-character version of wgetch(), available when
54 PDCurses is built with the PDC_WIDE option. It takes a pointer to a
55 wint_t rather than returning the key as an int, and instead returns
56 KEY_CODE_YES if the key is a function key. Otherwise, it returns OK
57 or ERR. It's important to check for KEY_CODE_YES, since regular wide
58 characters can have the same values as function key codes.
60 unget_wch() puts a wide character on the input queue.
62 PDC_get_key_modifiers() returns the keyboard modifiers (shift,
63 control, alt, numlock) effective at the time of the last getch()
64 call. Use the macros PDC_KEY_MODIFIER_* to determine which
65 modifier(s) were set. PDC_return_key_modifiers() tells getch() to
66 return modifier keys pressed alone as keystrokes (KEY_ALT_L, etc.).
67 These may not work on all platforms.
69 NOTE: getch() and ungetch() are implemented as macros, to avoid
70 conflict with many DOS compiler's runtime libraries.
72 ### Return Value
74 These functions return ERR or the value of the character, meta
75 character or function key token.
77 ### Portability
78 X/Open ncurses NetBSD
79 getch Y Y Y
80 wgetch Y Y Y
81 mvgetch Y Y Y
82 mvwgetch Y Y Y
83 ungetch Y Y Y
84 flushinp Y Y Y
85 get_wch Y Y Y
86 wget_wch Y Y Y
87 mvget_wch Y Y Y
88 mvwget_wch Y Y Y
89 unget_wch Y Y Y
90 PDC_get_key_modifiers - - -
92 **man-end****************************************************************/
94 #include <stdlib.h>
96 static int _get_box(int *y_start, int *y_end, int *x_start, int *x_end)
98 int start, end;
100 if (SP->sel_start < SP->sel_end)
102 start = SP->sel_start;
103 end = SP->sel_end;
105 else
107 start = SP->sel_end;
108 end = SP->sel_start;
111 *y_start = start / COLS;
112 *x_start = start % COLS;
114 *y_end = end / COLS;
115 *x_end = end % COLS;
117 return (end - start) + (*y_end - *y_start);
120 static void _highlight(void)
122 int i, j, y_start, y_end, x_start, x_end;
124 if (-1 == SP->sel_start)
125 return;
127 _get_box(&y_start, &y_end, &x_start, &x_end);
129 for (j = y_start; j <= y_end; j++)
130 for (i = (j == y_start ? x_start : 0);
131 i < (j == y_end ? x_end : COLS); i++)
132 curscr->_y[j][i] ^= A_REVERSE;
134 wrefresh(curscr);
137 static void _copy(void)
139 #ifdef PDC_WIDE
140 wchar_t *wtmp;
141 # define TMP wtmp
142 # define MASK A_CHARTEXT
143 #else
144 # define TMP tmp
145 # define MASK 0xff
146 #endif
147 char *tmp;
148 long pos;
149 int i, j, y_start, y_end, x_start, x_end, len;
151 if (-1 == SP->sel_start)
152 return;
154 len = _get_box(&y_start, &y_end, &x_start, &x_end);
156 if (!len)
157 return;
159 #ifdef PDC_WIDE
160 wtmp = malloc((len + 1) * sizeof(wchar_t));
161 len *= 3;
162 #endif
163 tmp = malloc(len + 1);
165 for (j = y_start, pos = 0; j <= y_end; j++)
167 for (i = (j == y_start ? x_start : 0);
168 i < (j == y_end ? x_end : COLS); i++)
169 TMP[pos++] = curscr->_y[j][i] & MASK;
171 while (y_start != y_end && pos > 0 && TMP[pos - 1] == 32)
172 pos--;
174 if (j < y_end)
175 TMP[pos++] = 10;
177 TMP[pos] = 0;
179 #ifdef PDC_WIDE
180 pos = PDC_wcstombs(tmp, wtmp, len);
181 #endif
183 PDC_setclipboard(tmp, pos);
184 free(tmp);
185 #ifdef PDC_WIDE
186 free(wtmp);
187 #endif
190 static int _paste(void)
192 #ifdef PDC_WIDE
193 wchar_t *wpaste;
194 # define PASTE wpaste
195 #else
196 # define PASTE paste
197 #endif
198 char *paste;
199 long len, newmax;
200 int key;
202 key = PDC_getclipboard(&paste, &len);
203 if (PDC_CLIP_SUCCESS != key || !len)
204 return -1;
206 #ifdef PDC_WIDE
207 wpaste = malloc(len * sizeof(wchar_t));
208 len = PDC_mbstowcs(wpaste, paste, len);
209 #endif
210 newmax = len + SP->c_ungind;
211 if (newmax > SP->c_ungmax)
213 SP->c_ungch = realloc(SP->c_ungch, newmax * sizeof(int));
214 if (!SP->c_ungch)
215 return -1;
216 SP->c_ungmax = newmax;
218 while (len > 1)
219 PDC_ungetch(PASTE[--len]);
220 key = *PASTE;
221 #ifdef PDC_WIDE
222 free(wpaste);
223 #endif
224 PDC_freeclipboard(paste);
225 SP->key_modifiers = 0;
227 return key;
230 static int _mouse_key(void)
232 int i, key = KEY_MOUSE, changes = SP->mouse_status.changes;
233 unsigned long mbe = SP->_trap_mbe;
235 /* Selection highlighting? */
237 if ((!mbe || SP->mouse_status.button[0] & BUTTON_SHIFT) && changes & 1)
239 i = SP->mouse_status.y * COLS + SP->mouse_status.x;
240 switch (SP->mouse_status.button[0] & BUTTON_ACTION_MASK)
242 case BUTTON_PRESSED:
243 _highlight();
244 SP->sel_start = SP->sel_end = i;
245 return -1;
246 case BUTTON_MOVED:
247 _highlight();
248 SP->sel_end = i;
249 _highlight();
250 return -1;
251 case BUTTON_RELEASED:
252 _copy();
253 return -1;
256 else if ((!mbe || SP->mouse_status.button[1] & BUTTON_SHIFT) &&
257 changes & 2 && (SP->mouse_status.button[1] &
258 BUTTON_ACTION_MASK) == BUTTON_CLICKED)
260 SP->key_code = FALSE;
261 return _paste();
264 /* Filter unwanted mouse events */
266 for (i = 0; i < 3; i++)
268 if (changes & (1 << i))
270 int shf = i * 5;
271 short button = SP->mouse_status.button[i] & BUTTON_ACTION_MASK;
273 if ( (!(mbe & (BUTTON1_PRESSED << shf)) &&
274 (button == BUTTON_PRESSED))
276 || (!(mbe & (BUTTON1_CLICKED << shf)) &&
277 (button == BUTTON_CLICKED))
279 || (!(mbe & (BUTTON1_DOUBLE_CLICKED << shf)) &&
280 (button == BUTTON_DOUBLE_CLICKED))
282 || (!(mbe & (BUTTON1_MOVED << shf)) &&
283 (button == BUTTON_MOVED))
285 || (!(mbe & (BUTTON1_RELEASED << shf)) &&
286 (button == BUTTON_RELEASED))
288 SP->mouse_status.changes ^= (1 << i);
292 if (changes & PDC_MOUSE_MOVED)
294 if (!(mbe & (BUTTON1_MOVED|BUTTON2_MOVED|BUTTON3_MOVED)))
295 SP->mouse_status.changes ^= PDC_MOUSE_MOVED;
298 if (changes & (PDC_MOUSE_WHEEL_UP|PDC_MOUSE_WHEEL_DOWN))
300 if (!(mbe & MOUSE_WHEEL_SCROLL))
301 SP->mouse_status.changes &=
302 ~(PDC_MOUSE_WHEEL_UP|PDC_MOUSE_WHEEL_DOWN);
305 if (!changes)
306 return -1;
308 /* Check for click in slk area */
310 i = PDC_mouse_in_slk(SP->mouse_status.y, SP->mouse_status.x);
312 if (i)
314 if (SP->mouse_status.button[0] & (BUTTON_PRESSED|BUTTON_CLICKED))
315 key = KEY_F(i);
316 else
317 key = -1;
320 return key;
323 int wgetch(WINDOW *win)
325 int key, waitcount;
327 PDC_LOG(("wgetch() - called\n"));
329 if (!win || !SP)
330 return ERR;
332 waitcount = 0;
334 /* set the number of 1/20th second napms() calls */
336 if (SP->delaytenths)
337 waitcount = 2 * SP->delaytenths;
338 else
339 if (win->_delayms)
341 /* Can't really do millisecond intervals, so delay in
342 1/20ths of a second (50ms) */
344 waitcount = win->_delayms / 50;
345 if (!waitcount)
346 waitcount = 1;
349 /* refresh window when wgetch is called if there have been changes
350 to it and it is not a pad */
352 if (!(win->_flags & _PAD) && ((!win->_leaveit &&
353 (win->_begx + win->_curx != SP->curscol ||
354 win->_begy + win->_cury != SP->cursrow)) || is_wintouched(win)))
355 wrefresh(win);
357 /* if ungotten char exists, remove and return it */
359 if (SP->c_ungind)
360 return SP->c_ungch[--(SP->c_ungind)];
362 /* if normal and data in buffer */
364 if ((!SP->raw_inp && !SP->cbreak) && (SP->c_gindex < SP->c_pindex))
365 return SP->c_buffer[SP->c_gindex++];
367 /* prepare to buffer data */
369 SP->c_pindex = 0;
370 SP->c_gindex = 0;
372 /* to get here, no keys are buffered. go and get one. */
374 for (;;) /* loop for any buffering */
376 /* is there a keystroke ready? */
378 if (!PDC_check_key())
380 /* if not, handle timeout() and halfdelay() */
382 if (SP->delaytenths || win->_delayms)
384 if (!waitcount)
385 return ERR;
387 waitcount--;
389 else
390 if (win->_nodelay)
391 return ERR;
393 napms(50); /* sleep for 1/20th second */
394 continue; /* then check again */
397 /* if there is, fetch it */
399 key = PDC_get_key();
401 /* copy or paste? */
403 if (SP->key_modifiers & PDC_KEY_MODIFIER_SHIFT)
405 if (0x03 == key)
407 _copy();
408 continue;
410 else if (0x16 == key)
411 key = _paste();
414 /* filter mouse events; translate mouse clicks in the slk
415 area to function keys */
417 if (SP->key_code && key == KEY_MOUSE)
418 key = _mouse_key();
420 /* filter special keys if not in keypad mode */
422 if (SP->key_code && !win->_use_keypad)
423 key = -1;
425 /* unwanted key? loop back */
427 if (key == -1)
428 continue;
430 _highlight();
431 SP->sel_start = SP->sel_end = -1;
433 /* translate CR */
435 if (key == '\r' && SP->autocr && !SP->raw_inp)
436 key = '\n';
438 /* if echo is enabled */
440 if (SP->echo && !SP->key_code)
442 waddch(win, key);
443 wrefresh(win);
446 /* if no buffering */
448 if (SP->raw_inp || SP->cbreak)
449 return key;
451 /* if no overflow, put data in buffer */
453 if (key == '\b')
455 if (SP->c_pindex > SP->c_gindex)
456 SP->c_pindex--;
458 else
459 if (SP->c_pindex < _INBUFSIZ - 2)
460 SP->c_buffer[SP->c_pindex++] = key;
462 /* if we got a line */
464 if (key == '\n' || key == '\r')
465 return SP->c_buffer[SP->c_gindex++];
469 int mvgetch(int y, int x)
471 PDC_LOG(("mvgetch() - called\n"));
473 if (move(y, x) == ERR)
474 return ERR;
476 return wgetch(stdscr);
479 int mvwgetch(WINDOW *win, int y, int x)
481 PDC_LOG(("mvwgetch() - called\n"));
483 if (wmove(win, y, x) == ERR)
484 return ERR;
486 return wgetch(win);
489 int PDC_ungetch(int ch)
491 PDC_LOG(("ungetch() - called\n"));
493 if (SP->c_ungind >= SP->c_ungmax) /* pushback stack full */
494 return ERR;
496 SP->c_ungch[SP->c_ungind++] = ch;
498 return OK;
501 int flushinp(void)
503 PDC_LOG(("flushinp() - called\n"));
505 if (!SP)
506 return ERR;
508 PDC_flushinp();
510 SP->c_gindex = 1; /* set indices to kill buffer */
511 SP->c_pindex = 0;
512 SP->c_ungind = 0; /* clear SP->c_ungch array */
514 return OK;
517 unsigned long PDC_get_key_modifiers(void)
519 PDC_LOG(("PDC_get_key_modifiers() - called\n"));
521 if (!SP)
522 return ERR;
524 return SP->key_modifiers;
527 int PDC_return_key_modifiers(bool flag)
529 PDC_LOG(("PDC_return_key_modifiers() - called\n"));
531 if (!SP)
532 return ERR;
534 SP->return_key_modifiers = flag;
535 return PDC_modifiers_set();
538 #ifdef PDC_WIDE
539 int wget_wch(WINDOW *win, wint_t *wch)
541 int key;
543 PDC_LOG(("wget_wch() - called\n"));
545 if (!wch)
546 return ERR;
548 key = wgetch(win);
550 if (key == ERR)
551 return ERR;
553 *wch = key;
555 return SP->key_code ? KEY_CODE_YES : OK;
558 int get_wch(wint_t *wch)
560 PDC_LOG(("get_wch() - called\n"));
562 return wget_wch(stdscr, wch);
565 int mvget_wch(int y, int x, wint_t *wch)
567 PDC_LOG(("mvget_wch() - called\n"));
569 if (move(y, x) == ERR)
570 return ERR;
572 return wget_wch(stdscr, wch);
575 int mvwget_wch(WINDOW *win, int y, int x, wint_t *wch)
577 PDC_LOG(("mvwget_wch() - called\n"));
579 if (wmove(win, y, x) == ERR)
580 return ERR;
582 return wget_wch(win, wch);
585 int unget_wch(const wchar_t wch)
587 return PDC_ungetch(wch);
589 #endif