xref: /netbsd-src/lib/libcurses/get_wch.c (revision 0df165c04d0a9ca1adde9ed2b890344c937954a6)
1 /*   $NetBSD: get_wch.c,v 1.4 2007/11/18 10:01:04 jdc Exp $ */
2 
3 /*
4  * Copyright (c) 2005 The NetBSD Foundation Inc.
5  * All rights reserved.
6  *
7  * This code is derived from code donated to the NetBSD Foundation
8  * by Ruibiao Qiu <ruibiao@arl.wustl.edu,ruibiao@gmail.com>.
9  *
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *	notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *	notice, this list of conditions and the following disclaimer in the
18  *	documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the NetBSD Foundation nor the names of its
20  *	contributors may be used to endorse or promote products derived
21  *	from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
24  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #include <sys/cdefs.h>
38 #ifndef lint
39 __RCSID("$NetBSD: get_wch.c,v 1.4 2007/11/18 10:01:04 jdc Exp $");
40 #endif						  /* not lint */
41 
42 #include <string.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <stdio.h>
46 #include "curses.h"
47 #include "curses_private.h"
48 #include "keymap.h"
49 
50 static short   wstate;		  /* state of the wcinkey function */
51 extern short state;		/* storage declared in getch.c */
52 
53 /* prototypes for private functions */
54 static int inkey(wchar_t *wc, int to, int delay);
55 
56 /*
57  * __init_get_wch - initialise all the pointers & structures needed to make
58  * get_wch work in keypad mode.
59  *
60  */
61 void
62 __init_get_wch(SCREEN *screen)
63 {
64 #ifndef HAVE_WCHAR
65 	return;
66 #else
67 	wstate = INKEY_NORM;
68 	memset( &screen->cbuf, 0, MAX_CBUF_SIZE * sizeof( int ));
69 	screen->cbuf_head = screen->cbuf_tail = screen->cbuf_cur = 0;
70 #endif /* HAVE_WCHAR */
71 }
72 
73 
74 /*
75  * inkey - do the work to process keyboard input, check for multi-key
76  * sequences and return the appropriate symbol if we get a match.
77  *
78  */
79 
80 int
81 inkey(wchar_t *wc, int to, int delay)
82 {
83 #ifndef HAVE_WCHAR
84 	return ERR;
85 #else
86 	wchar_t		 k = 0;
87 	int		  c, mapping, ret = 0;
88 	size_t	  mlen = 0;
89 	keymap_t	*current = _cursesi_screen->base_keymap;
90 	FILE		*infd = _cursesi_screen->infd;
91 	int		 *start = &_cursesi_screen->cbuf_head,
92 				*working = &_cursesi_screen->cbuf_cur,
93 				*end = &_cursesi_screen->cbuf_tail;
94 	char		*inbuf = &_cursesi_screen->cbuf[ 0 ];
95 
96 /*  int	ESCDELAY = 300;*/	/* Delay in ms between keys for esc seq's */
97 	ESCDELAY = 300;
98 
99 	for (;;) { /* loop until we get a complete key sequence */
100 		if (wstate == INKEY_NORM) {
101 			if (delay && __timeout(delay) == ERR)
102 				return ERR;
103 			c = getchar();
104 			if (_cursesi_screen->resized) {
105 				if (c != WEOF) /* was -1 */
106 					unget_wch(c);
107 				_cursesi_screen->resized = 0;
108 				clearerr(infd);
109 				*wc = KEY_RESIZE;
110 				return KEY_CODE_YES;
111 			}
112 			if (c == WEOF) {
113 				clearerr(infd);
114 				return ERR;
115 			}
116 
117 			if (delay && (__notimeout() == ERR))
118 				return ERR;
119 
120 			k = (wchar_t) c;
121 #ifdef DEBUG
122 			__CTRACE(__CTRACE_INPUT,
123 			    "inkey (wstate normal) got '%s'\n", unctrl(k));
124 #endif
125 
126 			inbuf[ *end ] = k;
127 			*end = ( *end + 1 ) % MAX_CBUF_SIZE;
128 			*working = *start;
129 			wstate = INKEY_ASSEMBLING; /* go to assembling state */
130 #ifdef DEBUG
131 			__CTRACE(__CTRACE_INPUT,
132 			    "inkey: NORM=>ASSEMBLING: start(%d), "
133 			    "current(%d), end(%d)\n", *start, *working, *end);
134 #endif /* DEBUG */
135 		} else if (wstate == INKEY_BACKOUT) {
136 			k = inbuf[*working];
137 			*working = ( *working + 1 ) % MAX_CBUF_SIZE;
138 			if (*working == *end) {	/* see if run out of keys */
139 				/* if so, switch to assembling */
140 				wstate = INKEY_ASSEMBLING;
141 #ifdef DEBUG
142 				__CTRACE(__CTRACE_INPUT,
143 				    "inkey: BACKOUT=>ASSEMBLING, start(%d), "
144 				    "current(%d), end(%d)\n",
145 				    *start, *working, *end);
146 #endif /* DEBUG */
147 			}
148 		} else if (wstate == INKEY_ASSEMBLING) {
149 			/* assembling a key sequence */
150 			if (delay) {
151 				if (__timeout(to ? (ESCDELAY / 100) : delay)
152 						== ERR)
153 					return ERR;
154 			} else {
155 				if (to && (__timeout(ESCDELAY / 100) == ERR))
156 					return ERR;
157 			}
158 
159 			c = getchar();
160 			if (_cursesi_screen->resized) {
161 				if (c != -1)
162 					unget_wch(c);
163 				_cursesi_screen->resized = 0;
164 				clearerr(infd);
165 				*wc = KEY_RESIZE;
166 				return KEY_CODE_YES;
167 			}
168 			if (ferror(infd)) {
169 				clearerr(infd);
170 				return ERR;
171 			}
172 
173 			if ((to || delay) && (__notimeout() == ERR))
174 				return ERR;
175 
176 			k = (wchar_t) c;
177 #ifdef DEBUG
178 			__CTRACE(__CTRACE_INPUT,
179 			    "inkey (wstate assembling) got '%s'\n", unctrl(k));
180 #endif /* DEBUG */
181 			if (feof(infd)) { /* inter-char T/O, start backout */
182 				clearerr(infd);
183 				if (*start == *end)
184 					/* no chars in the buffer, restart */
185 					continue;
186 
187 				k = inbuf[*start];
188 				wstate = INKEY_TIMEOUT;
189 #ifdef DEBUG
190 				__CTRACE(__CTRACE_INPUT,
191 				    "inkey: ASSEMBLING=>TIMEOUT, start(%d), "
192 				    "current(%d), end(%d)\n",
193 				    *start, *working, *end);
194 #endif /* DEBUG */
195 			} else {
196 				inbuf[ *end ] = k;
197 				*working = *end;
198 				*end = ( *end + 1 ) % MAX_CBUF_SIZE;
199 #ifdef DEBUG
200 				__CTRACE(__CTRACE_INPUT,
201 				    "inkey: ASSEMBLING: start(%d), "
202 				    "current(%d), end(%d)",
203 				    *start, *working, *end);
204 #endif /* DEBUG */
205 			}
206 		} else if (wstate == INKEY_WCASSEMBLING) {
207 			/* assembling a wide char sequence */
208 			if (delay) {
209 				if (__timeout(to ? (ESCDELAY / 100) : delay)
210 						== ERR)
211 					return ERR;
212 			} else {
213 				if (to && (__timeout(ESCDELAY / 100) == ERR))
214 					return ERR;
215 			}
216 
217 			c = getchar();
218 			if (_cursesi_screen->resized) {
219 				if (c != -1)
220 					unget_wch(c);
221 				_cursesi_screen->resized = 0;
222 				clearerr(infd);
223 				*wc = KEY_RESIZE;
224 				return KEY_CODE_YES;
225 			}
226 			if (ferror(infd)) {
227 				clearerr(infd);
228 				return ERR;
229 			}
230 
231 			if ((to || delay) && (__notimeout() == ERR))
232 				return ERR;
233 
234 			k = (wchar_t) c;
235 #ifdef DEBUG
236 			__CTRACE(__CTRACE_INPUT,
237 			    "inkey (wstate wcassembling) got '%s'\n",
238 				unctrl(k));
239 #endif
240 			if (feof(infd)) { /* inter-char T/O, start backout */
241 				clearerr(infd);
242 				if (*start == *end)
243 					/* no chars in the buffer, restart */
244 					continue;
245 
246 				*wc = inbuf[*start];
247 				*working = *start
248 					= ( *start + 1 ) % MAX_CBUF_SIZE;
249 				if (*start == *end) {
250 					state = wstate = INKEY_NORM;
251 #ifdef DEBUG
252 					__CTRACE(__CTRACE_INPUT,
253 					    "inkey: WCASSEMBLING=>NORM, "
254 					    "start(%d), current(%d), end(%d)",
255 					    *start, *working, *end);
256 #endif /* DEBUG */
257 				} else {
258 					state = wstate = INKEY_BACKOUT;
259 #ifdef DEBUG
260 					__CTRACE(__CTRACE_INPUT,
261 					    "inkey: WCASSEMBLING=>BACKOUT, "
262 					    "start(%d), current(%d), end(%d)",
263 					    *start, *working, *end);
264 #endif /* DEBUG */
265 				}
266 				return OK;
267 			} else {
268 				/* assembling wide characters */
269 				inbuf[ *end ] = k;
270 				*working = *end;
271 				*end = ( *end + 1 ) % MAX_CBUF_SIZE;
272 #ifdef DEBUG
273 				__CTRACE(__CTRACE_INPUT,
274 				    "inkey: WCASSEMBLING[head(%d), "
275 				    "urrent(%d), tail(%d)]\n",
276 				    *start, *working, *end);
277 #endif /* DEBUG */
278 				ret = (int) mbrtowc( wc, inbuf + (*working), 1,
279 					&_cursesi_screen->sp );
280 #ifdef DEBUG
281 				__CTRACE(__CTRACE_INPUT,
282 				    "inkey: mbrtowc returns %d, wc(%x)\n",
283 				    ret, *wc );
284 #endif /* DEBUG */
285 				if ( ret == -2 ) {
286 					*working = (*working + 1)
287 						% MAX_CBUF_SIZE;
288 					continue;
289 				}
290 				if ( ret == 0 )
291 					ret = 1;
292 				if ( ret == -1 ) {
293 					/* return the 1st character we know */
294 					*wc = inbuf[ *start ];
295 					*working = *start = ( *start + 1 ) % MAX_CBUF_SIZE;
296 #ifdef DEBUG
297 					__CTRACE(__CTRACE_INPUT,
298 					    "inkey: Invalid wide char(%x) "
299 					    "[head(%d), current(%d), "
300 					    "tail(%d)]\n",
301 					    *wc, *start, *working, *end);
302 #endif /* DEBUG */
303 				} else { /* > 0 */
304 					/* return the wide character */
305 					*start = *working
306 					       = (*working + ret)%MAX_CBUF_SIZE;
307 #ifdef DEBUG
308 					__CTRACE(__CTRACE_INPUT,
309 					    "inkey: Wide char found(%x) "
310 					    "[head(%d), current(%d), "
311 					    "tail(%d)]\n",
312 					    *wc, *start, *working, *end);
313 #endif /* DEBUG */
314 				}
315 
316 				if (*start == *end) {	/* only one char processed */
317 					state = wstate = INKEY_NORM;
318 #ifdef DEBUG
319 					__CTRACE(__CTRACE_INPUT,
320 					    "inkey: WCASSEMBLING=>NORM, "
321 					    "start(%d), current(%d), end(%d)",
322 					    *start, *working, *end);
323 #endif /* DEBUG */
324 				} else {
325 					/* otherwise we must have more than one char to backout */
326 					state = wstate = INKEY_BACKOUT;
327 #ifdef DEBUG
328 					__CTRACE(__CTRACE_INPUT,
329 					    "inkey: WCASSEMBLING=>BACKOUT, "
330 					    "start(%d), current(%d), end(%d)",
331 					    *start, *working, *end);
332 #endif /* DEBUG */
333 				}
334 				return OK;
335 			}
336 		} else {
337 			fprintf(stderr, "Inkey wstate screwed - exiting!!!");
338 			exit(2);
339 		}
340 
341 		/*
342 		 * Check key has no special meaning and we have not
343 		 * timed out and the key has not been disabled
344 		 */
345 		mapping = current->mapping[k];
346 		if (((wstate == INKEY_TIMEOUT) || (mapping < 0))
347 				|| ((current->key[mapping]->type
348 					== KEYMAP_LEAF)
349 				&& (current->key[mapping]->enable == FALSE))) {
350 			/* wide character specific code */
351 #ifdef DEBUG
352 			__CTRACE(__CTRACE_INPUT,
353 			    "inkey: Checking for wide char\n");
354 #endif /* DEBUG */
355 			mbrtowc( NULL, NULL, 1, &_cursesi_screen->sp );
356 			*working = *start;
357 			mlen = *end > *working ?
358 				*end - *working : MAX_CBUF_SIZE - *working;
359 			if ( !mlen )
360 				return ERR;
361 #ifdef DEBUG
362 			__CTRACE(__CTRACE_INPUT,
363 			    "inkey: Check wide char[head(%d), "
364 			    "current(%d), tail(%d), mlen(%ld)]\n",
365 			    *start, *working, *end, (long) mlen);
366 #endif /* DEBUG */
367 			ret = (int) mbrtowc( wc, inbuf + (*working), mlen,
368 				&_cursesi_screen->sp );
369 #ifdef DEBUG
370 			__CTRACE(__CTRACE_INPUT,
371 			    "inkey: mbrtowc returns %d, wc(%x)\n", ret, *wc);
372 #endif /* DEBUG */
373 			if ( ret == -2 && *end < *working ) {
374 				/* second half of a wide character */
375 				*working = 0;
376 				mlen = *end;
377 				if ( mlen )
378 					ret = (int) mbrtowc( wc, inbuf, mlen,
379 						&_cursesi_screen->sp );
380 			}
381 			if ( ret == -2 && wstate != INKEY_TIMEOUT ) {
382 				*working = (*working + (int) mlen)
383 					% MAX_CBUF_SIZE;
384 				wstate = INKEY_WCASSEMBLING;
385 				continue;
386 			}
387 			if ( ret == 0 )
388 				ret = 1;
389 			if ( ret == -1 ) {
390 				/* return the first key we know about */
391 				*wc = inbuf[ *start ];
392 				*working = *start
393 					= ( *start + 1 ) % MAX_CBUF_SIZE;
394 #ifdef DEBUG
395 				__CTRACE(__CTRACE_INPUT,
396 				    "inkey: Invalid wide char(%x)[head(%d), "
397 				    "current(%d), tail(%d)]\n",
398 				    *wc, *start, *working, *end);
399 #endif /* DEBUG */
400 			} else { /* > 0 */
401 				/* return the wide character */
402 				*start = *working
403 					= ( *working + ret ) % MAX_CBUF_SIZE;
404 #ifdef DEBUG
405 				__CTRACE(__CTRACE_INPUT,
406 				    "inkey: Wide char found(%x)[head(%d), "
407 				    "current(%d), tail(%d)]\n",
408 				    *wc, *start, *working, *end);
409 #endif /* DEBUG */
410 			}
411 
412 			if (*start == *end) {	/* only one char processed */
413 				state = wstate = INKEY_NORM;
414 #ifdef DEBUG
415 				__CTRACE(__CTRACE_INPUT,
416 				    "inkey: Empty cbuf=>NORM, "
417 				    "start(%d), current(%d), end(%d)\n",
418 				    *start, *working, *end);
419 #endif /* DEBUG */
420 			} else {
421 				/* otherwise we must have more than one char to backout */
422 				state = wstate = INKEY_BACKOUT;
423 #ifdef DEBUG
424 				__CTRACE(__CTRACE_INPUT,
425 				    "inkey: Non-empty cbuf=>BACKOUT, "
426 				    "start(%d), current(%d), end(%d)\n",
427 				    *start, *working, *end);
428 #endif /* DEBUG */
429 			}
430 			return OK;
431 		} else {	/* must be part of a multikey sequence */
432 					/* check for completed key sequence */
433 			if (current->key[current->mapping[k]]->type
434 					== KEYMAP_LEAF) {
435 				/* eat the key sequence in cbuf */
436 				*start = *working = ( *working + 1 ) % MAX_CBUF_SIZE;
437 
438 				/* check if inbuf empty now */
439 #ifdef DEBUG
440 				__CTRACE(__CTRACE_INPUT,
441 				    "inkey: Key found(%s)\n",
442 				    key_name(current->key[mapping]->value.symbol));
443 #endif /* DEBUG */
444 				if (*start == *end) {
445 					/* if it is go back to normal */
446 					state = wstate = INKEY_NORM;
447 #ifdef DEBUG
448 					__CTRACE(__CTRACE_INPUT,
449 					    "[inkey]=>NORM, start(%d), "
450 					    "current(%d), end(%d)",
451 					    *start, *working, *end);
452 #endif /* DEBUG */
453 				} else {
454 					/* otherwise go to backout state */
455 					state = wstate = INKEY_BACKOUT;
456 #ifdef DEBUG
457 					__CTRACE(__CTRACE_INPUT,
458 					    "[inkey]=>BACKOUT, start(%d), "
459 					    "current(%d), end(%d)",
460 					    *start, *working, *end );
461 #endif /* DEBUG */
462 				}
463 
464 				/* return the symbol */
465 				*wc = current->key[mapping]->value.symbol;
466 				return KEY_CODE_YES;
467 			} else {
468 				/* Step to next part of multi-key sequence */
469 				current = current->key[current->mapping[k]]->value.next;
470 			}
471 		}
472 	}
473 #endif /* HAVE_WCHAR */
474 }
475 
476 /*
477  * get_wch --
478  *	Read in a wide character from stdscr.
479  */
480 int
481 get_wch(wint_t *ch)
482 {
483 #ifndef HAVE_WCHAR
484 	return ERR;
485 #else
486 	return wget_wch(stdscr, ch);
487 #endif /* HAVE_WCHAR */
488 }
489 
490 /*
491  * mvget_wch --
492  *	  Read in a character from stdscr at the given location.
493  */
494 int
495 mvget_wch(int y, int x, wint_t *ch)
496 {
497 #ifndef HAVE_WCHAR
498 	return ERR;
499 #else
500 	return mvwget_wch(stdscr, y, x, ch);
501 #endif /* HAVE_WCHAR */
502 }
503 
504 /*
505  * mvwget_wch --
506  *	  Read in a character from stdscr at the given location in the
507  *	  given window.
508  */
509 int
510 mvwget_wch(WINDOW *win, int y, int x, wint_t *ch)
511 {
512 #ifndef HAVE_WCHAR
513 	return ERR;
514 #else
515 	if (wmove(win, y, x) == ERR)
516 		return ERR;
517 
518 	return wget_wch(win, ch);
519 #endif /* HAVE_WCHAR */
520 }
521 
522 /*
523  * wget_wch --
524  *	Read in a wide character from the window.
525  */
526 int
527 wget_wch(WINDOW *win, wint_t *ch)
528 {
529 #ifndef HAVE_WCHAR
530 	return ERR;
531 #else
532 	int ret, weset;
533 	int c;
534 	FILE *infd = _cursesi_screen->infd;
535 	cchar_t wc;
536 	wchar_t inp, ws[ 2 ];
537 
538 	if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN)
539 			&& win->curx == win->maxx - 1
540 			&& win->cury == win->maxy - 1
541 			&& __echoit)
542 		return (ERR);
543 
544 	if (is_wintouched(win))
545 		wrefresh(win);
546 #ifdef DEBUG
547 	__CTRACE(__CTRACE_INPUT, "wget_wch: __echoit = %d, "
548 	    "__rawmode = %d, __nl = %d, flags = %#.4x\n",
549 	    __echoit, __rawmode, _cursesi_screen->nl, win->flags);
550 #endif
551 	if (__echoit && !__rawmode) {
552 		cbreak();
553 		weset = 1;
554 	} else
555 		weset = 0;
556 
557 	__save_termios();
558 
559 	if (win->flags & __KEYPAD) {
560 		switch (win->delay) {
561 			case -1:
562 				ret = inkey(&inp,
563 					win->flags & __NOTIMEOUT ? 0 : 1, 0);
564 				break;
565 			case 0:
566 				if (__nodelay() == ERR) {
567 					__restore_termios();
568 					return ERR;
569 				}
570 				ret = inkey(&inp, 0, 0);
571 				break;
572 			default:
573 				ret = inkey(&inp,
574 					win->flags & __NOTIMEOUT ? 0 : 1,
575 					win->delay);
576 				break;
577 		}
578 		if ( ret == ERR )
579 			return ERR;
580 	} else {
581 		switch (win->delay) {
582 			case -1:
583 				break;
584 			case 0:
585 				if (__nodelay() == ERR) {
586 					__restore_termios();
587 					return ERR;
588 				}
589 				break;
590 			default:
591 				if (__timeout(win->delay) == ERR) {
592 					__restore_termios();
593 					return ERR;
594 				}
595 				break;
596 		}
597 
598 		c = getwchar();
599 		if (_cursesi_screen->resized) {
600 			if (c != -1)
601 				unget_wch(c);
602 			_cursesi_screen->resized = 0;
603 			clearerr(infd);
604 			__restore_termios();
605 			*ch = KEY_RESIZE;
606 			return KEY_CODE_YES;
607 		}
608 		if (feof(infd)) {
609 			clearerr(infd);
610 			__restore_termios();
611 			return ERR;	/* we have timed out */
612 		}
613 
614 		if (ferror(infd)) {
615 			clearerr(infd);
616 			return ERR;
617 		} else {
618             ret = c;
619 			inp = c;
620 		}
621 	}
622 #ifdef DEBUG
623 	if (inp > 255)
624 		/* we have a key symbol - treat it differently */
625 		/* XXXX perhaps __unctrl should be expanded to include
626 		 * XXXX the keysyms in the table....
627 		 */
628 		__CTRACE(__CTRACE_INPUT, "wget_wch assembled keysym 0x%x\n",
629 		    inp);
630 	else
631 		__CTRACE(__CTRACE_INPUT, "wget_wch got '%s'\n", unctrl(inp));
632 #endif
633 	if (win->delay > -1) {
634 		if (__delay() == ERR) {
635 			__restore_termios();
636 			return ERR;
637 		}
638 	}
639 
640 	__restore_termios();
641 
642 	if (__echoit) {
643 		if ( ret == KEY_CODE_YES ) {
644 			/* handle [DEL], [BS], and [LEFT] */
645 			if ( win->curx &&
646 					( inp == KEY_DC ||
647 					  inp == KEY_BACKSPACE ||
648 					  inp == KEY_LEFT )) {
649 				wmove( win, win->cury, win->curx - 1 );
650 				wdelch( win );
651 			}
652 		} else {
653 			ws[ 0 ] = inp, ws[ 1 ] = L'\0';
654 			setcchar( &wc, ws, win->wattr, 0, NULL );
655 			wadd_wch( win, &wc );
656 		}
657 	}
658 
659 	if (weset)
660 		nocbreak();
661 
662 	if (_cursesi_screen->nl && inp == 13)
663 		inp = 10;
664 
665 	*ch = inp;
666 
667 	if ( ret == KEY_CODE_YES )
668 		return KEY_CODE_YES;
669 	return ( inp < 0 ? ERR : OK );
670 #endif /* HAVE_WCHAR */
671 }
672 
673 /*
674  * unget_wch --
675  *	 Put the wide character back into the input queue.
676  */
677 int
678 unget_wch(const wchar_t c)
679 {
680 	return
681 		( int )((ungetwc((wint_t)c, _cursesi_screen->infd) == WEOF) ?
682 				ERR : OK);
683 }
684