1*d6782af8Suwe /* $NetBSD: get_wch.c,v 1.24 2020/07/06 23:33:38 uwe Exp $ */ 2fa0b432bSblymn 3fa0b432bSblymn /* 4fa0b432bSblymn * Copyright (c) 2005 The NetBSD Foundation Inc. 5fa0b432bSblymn * All rights reserved. 6fa0b432bSblymn * 7fa0b432bSblymn * This code is derived from code donated to the NetBSD Foundation 8fa0b432bSblymn * by Ruibiao Qiu <ruibiao@arl.wustl.edu,ruibiao@gmail.com>. 9fa0b432bSblymn * 10fa0b432bSblymn * 11fa0b432bSblymn * Redistribution and use in source and binary forms, with or without 12fa0b432bSblymn * modification, are permitted provided that the following conditions 13fa0b432bSblymn * are met: 14fa0b432bSblymn * 1. Redistributions of source code must retain the above copyright 15fa0b432bSblymn * notice, this list of conditions and the following disclaimer. 16fa0b432bSblymn * 2. Redistributions in binary form must reproduce the above copyright 17fa0b432bSblymn * notice, this list of conditions and the following disclaimer in the 18fa0b432bSblymn * documentation and/or other materials provided with the distribution. 19fa0b432bSblymn * 3. Neither the name of the NetBSD Foundation nor the names of its 20fa0b432bSblymn * contributors may be used to endorse or promote products derived 21fa0b432bSblymn * from this software without specific prior written permission. 22fa0b432bSblymn * 23fa0b432bSblymn * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 24fa0b432bSblymn * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 25fa0b432bSblymn * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 26fa0b432bSblymn * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27fa0b432bSblymn * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28fa0b432bSblymn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29fa0b432bSblymn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30fa0b432bSblymn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31fa0b432bSblymn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32fa0b432bSblymn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33fa0b432bSblymn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34fa0b432bSblymn * SUCH DAMAGE. 35fa0b432bSblymn */ 36fa0b432bSblymn 37fa0b432bSblymn #include <sys/cdefs.h> 38fa0b432bSblymn #ifndef lint 39*d6782af8Suwe __RCSID("$NetBSD: get_wch.c,v 1.24 2020/07/06 23:33:38 uwe Exp $"); 40fa0b432bSblymn #endif /* not lint */ 41fa0b432bSblymn 428df9a300Srin #include <errno.h> 43fa0b432bSblymn #include <string.h> 44fa0b432bSblymn #include <stdlib.h> 45fa0b432bSblymn #include <unistd.h> 46fa0b432bSblymn #include <stdio.h> 47fa0b432bSblymn #include "curses.h" 48fa0b432bSblymn #include "curses_private.h" 49fa0b432bSblymn #include "keymap.h" 50fa0b432bSblymn 51fa0b432bSblymn static short wstate; /* state of the wcinkey function */ 522a9f52daSrin extern short _cursesi_state; /* storage declared in getch.c */ 53fa0b432bSblymn 54fa0b432bSblymn /* prototypes for private functions */ 55fa0b432bSblymn static int inkey(wchar_t *wc, int to, int delay); 564aeb00ceSroy static wint_t __fgetwc_resize(FILE *infd, bool *resized); 57fa0b432bSblymn 58fa0b432bSblymn /* 59fa0b432bSblymn * __init_get_wch - initialise all the pointers & structures needed to make 60fa0b432bSblymn * get_wch work in keypad mode. 61fa0b432bSblymn * 62fa0b432bSblymn */ 63fa0b432bSblymn void 64fa0b432bSblymn __init_get_wch(SCREEN *screen) 65fa0b432bSblymn { 66fa0b432bSblymn wstate = INKEY_NORM; 67414be921Sblymn memset(&screen->cbuf, 0, sizeof(screen->cbuf)); 68fa0b432bSblymn screen->cbuf_head = screen->cbuf_tail = screen->cbuf_cur = 0; 69fa0b432bSblymn } 70fa0b432bSblymn 71fa0b432bSblymn 72fa0b432bSblymn /* 73fa0b432bSblymn * inkey - do the work to process keyboard input, check for multi-key 74fa0b432bSblymn * sequences and return the appropriate symbol if we get a match. 75fa0b432bSblymn * 76fa0b432bSblymn */ 77619b7f0eSjdc static int 78fa0b432bSblymn inkey(wchar_t *wc, int to, int delay) 79fa0b432bSblymn { 80fa0b432bSblymn wchar_t k = 0; 81fa0b432bSblymn int c, mapping, ret = 0; 82fa0b432bSblymn size_t mlen = 0; 83fa0b432bSblymn keymap_t *current = _cursesi_screen->base_keymap; 84fa0b432bSblymn FILE *infd = _cursesi_screen->infd; 85fa0b432bSblymn int *start = &_cursesi_screen->cbuf_head, 86fa0b432bSblymn *working = &_cursesi_screen->cbuf_cur, 87fa0b432bSblymn *end = &_cursesi_screen->cbuf_tail; 88fa0b432bSblymn char *inbuf = &_cursesi_screen->cbuf[ 0 ]; 89fa0b432bSblymn 907cc6075bSjdc #ifdef DEBUG 917cc6075bSjdc __CTRACE(__CTRACE_INPUT, "inkey (%p, %d, %d)\n", wc, to, delay); 927cc6075bSjdc #endif 93fa0b432bSblymn for (;;) { /* loop until we get a complete key sequence */ 94fa0b432bSblymn if (wstate == INKEY_NORM) { 95fa0b432bSblymn if (delay && __timeout(delay) == ERR) 96fa0b432bSblymn return ERR; 974aeb00ceSroy c = __fgetc_resize(infd); 984aeb00ceSroy if (c == ERR || c == KEY_RESIZE) { 99fa0b432bSblymn clearerr(infd); 1004aeb00ceSroy return c; 101fa0b432bSblymn } 102fa0b432bSblymn 103fa0b432bSblymn if (delay && (__notimeout() == ERR)) 104fa0b432bSblymn return ERR; 105fa0b432bSblymn 106fa0b432bSblymn k = (wchar_t)c; 107fa0b432bSblymn #ifdef DEBUG 108e124de36Sblymn __CTRACE(__CTRACE_INPUT, 109e124de36Sblymn "inkey (wstate normal) got '%s'\n", unctrl(k)); 110fa0b432bSblymn #endif 111fa0b432bSblymn 112fa0b432bSblymn inbuf[*end] = k; 113fa0b432bSblymn *end = (*end + 1) % MAX_CBUF_SIZE; 114fa0b432bSblymn *working = *start; 115fa0b432bSblymn wstate = INKEY_ASSEMBLING; /* go to assembling state */ 116fa0b432bSblymn #ifdef DEBUG 117e124de36Sblymn __CTRACE(__CTRACE_INPUT, 118e124de36Sblymn "inkey: NORM=>ASSEMBLING: start(%d), " 119e124de36Sblymn "current(%d), end(%d)\n", *start, *working, *end); 120fa0b432bSblymn #endif /* DEBUG */ 121fa0b432bSblymn } else if (wstate == INKEY_BACKOUT) { 122fa0b432bSblymn k = inbuf[*working]; 123fa0b432bSblymn *working = (*working + 1) % MAX_CBUF_SIZE; 124fa0b432bSblymn if (*working == *end) { /* see if run out of keys */ 125fa0b432bSblymn /* if so, switch to assembling */ 126fa0b432bSblymn wstate = INKEY_ASSEMBLING; 127fa0b432bSblymn #ifdef DEBUG 128e124de36Sblymn __CTRACE(__CTRACE_INPUT, 129e124de36Sblymn "inkey: BACKOUT=>ASSEMBLING, start(%d), " 130e124de36Sblymn "current(%d), end(%d)\n", 131fa0b432bSblymn *start, *working, *end); 132fa0b432bSblymn #endif /* DEBUG */ 133fa0b432bSblymn } 134fa0b432bSblymn } else if (wstate == INKEY_ASSEMBLING) { 135fa0b432bSblymn /* assembling a key sequence */ 136fa0b432bSblymn if (delay) { 137d3b3f557Sroy if (__timeout(to ? (ESCDELAY / 100) : delay) 138fa0b432bSblymn == ERR) 139fa0b432bSblymn return ERR; 140fa0b432bSblymn } else { 141d3b3f557Sroy if (to && (__timeout(ESCDELAY / 100) == ERR)) 142fa0b432bSblymn return ERR; 143fa0b432bSblymn } 144fa0b432bSblymn 1454aeb00ceSroy c = __fgetc_resize(infd); 146fa0b432bSblymn if (ferror(infd)) { 147fa0b432bSblymn clearerr(infd); 1484aeb00ceSroy return c; 149fa0b432bSblymn } 150fa0b432bSblymn 151fa0b432bSblymn if ((to || delay) && (__notimeout() == ERR)) 152fa0b432bSblymn return ERR; 153fa0b432bSblymn 154fa0b432bSblymn k = (wchar_t)c; 155fa0b432bSblymn #ifdef DEBUG 156e124de36Sblymn __CTRACE(__CTRACE_INPUT, 157e124de36Sblymn "inkey (wstate assembling) got '%s'\n", unctrl(k)); 158fa0b432bSblymn #endif /* DEBUG */ 159fa0b432bSblymn if (feof(infd)) { /* inter-char T/O, start backout */ 160fa0b432bSblymn clearerr(infd); 161fa0b432bSblymn if (*start == *end) 162fa0b432bSblymn /* no chars in the buffer, restart */ 163fa0b432bSblymn continue; 164fa0b432bSblymn 165fa0b432bSblymn k = inbuf[*start]; 166fa0b432bSblymn wstate = INKEY_TIMEOUT; 167fa0b432bSblymn #ifdef DEBUG 168e124de36Sblymn __CTRACE(__CTRACE_INPUT, 169e124de36Sblymn "inkey: ASSEMBLING=>TIMEOUT, start(%d), " 170e124de36Sblymn "current(%d), end(%d)\n", 171fa0b432bSblymn *start, *working, *end); 172fa0b432bSblymn #endif /* DEBUG */ 173fa0b432bSblymn } else { 174fa0b432bSblymn inbuf[*end] = k; 175fa0b432bSblymn *working = *end; 176fa0b432bSblymn *end = (*end + 1) % MAX_CBUF_SIZE; 177fa0b432bSblymn #ifdef DEBUG 178e124de36Sblymn __CTRACE(__CTRACE_INPUT, 179e124de36Sblymn "inkey: ASSEMBLING: start(%d), " 180e124de36Sblymn "current(%d), end(%d)", 181fa0b432bSblymn *start, *working, *end); 182fa0b432bSblymn #endif /* DEBUG */ 183fa0b432bSblymn } 184fa0b432bSblymn } else if (wstate == INKEY_WCASSEMBLING) { 1850f41cbdbSwiz /* assembling a wide-char sequence */ 186fa0b432bSblymn if (delay) { 187d3b3f557Sroy if (__timeout(to ? (ESCDELAY / 100) : delay) 188fa0b432bSblymn == ERR) 189fa0b432bSblymn return ERR; 190fa0b432bSblymn } else { 191d3b3f557Sroy if (to && (__timeout(ESCDELAY / 100) == ERR)) 192fa0b432bSblymn return ERR; 193fa0b432bSblymn } 194fa0b432bSblymn 1954aeb00ceSroy c = __fgetc_resize(infd); 196fa0b432bSblymn if (ferror(infd)) { 197fa0b432bSblymn clearerr(infd); 1984aeb00ceSroy return c; 199fa0b432bSblymn } 200fa0b432bSblymn 201fa0b432bSblymn if ((to || delay) && (__notimeout() == ERR)) 202fa0b432bSblymn return ERR; 203fa0b432bSblymn 204fa0b432bSblymn k = (wchar_t)c; 205fa0b432bSblymn #ifdef DEBUG 206e124de36Sblymn __CTRACE(__CTRACE_INPUT, 207e124de36Sblymn "inkey (wstate wcassembling) got '%s'\n", 208fa0b432bSblymn unctrl(k)); 209fa0b432bSblymn #endif 210fa0b432bSblymn if (feof(infd)) { /* inter-char T/O, start backout */ 211fa0b432bSblymn clearerr(infd); 212fa0b432bSblymn if (*start == *end) 213fa0b432bSblymn /* no chars in the buffer, restart */ 214fa0b432bSblymn continue; 215fa0b432bSblymn 216fa0b432bSblymn *wc = inbuf[*start]; 21780b412b0Sroy *working = *start = (*start +1) % MAX_CBUF_SIZE; 218fa0b432bSblymn if (*start == *end) { 2192a9f52daSrin _cursesi_state = wstate = INKEY_NORM; 220fa0b432bSblymn #ifdef DEBUG 221e124de36Sblymn __CTRACE(__CTRACE_INPUT, 222e124de36Sblymn "inkey: WCASSEMBLING=>NORM, " 223e124de36Sblymn "start(%d), current(%d), end(%d)", 224fa0b432bSblymn *start, *working, *end); 225fa0b432bSblymn #endif /* DEBUG */ 226fa0b432bSblymn } else { 2272a9f52daSrin _cursesi_state = wstate = INKEY_BACKOUT; 228fa0b432bSblymn #ifdef DEBUG 229e124de36Sblymn __CTRACE(__CTRACE_INPUT, 230e124de36Sblymn "inkey: WCASSEMBLING=>BACKOUT, " 231e124de36Sblymn "start(%d), current(%d), end(%d)", 232fa0b432bSblymn *start, *working, *end); 233fa0b432bSblymn #endif /* DEBUG */ 234fa0b432bSblymn } 235fa0b432bSblymn return OK; 236fa0b432bSblymn } else { 237fa0b432bSblymn /* assembling wide characters */ 238fa0b432bSblymn inbuf[*end] = k; 239fa0b432bSblymn *working = *end; 240fa0b432bSblymn *end = (*end + 1) % MAX_CBUF_SIZE; 241fa0b432bSblymn #ifdef DEBUG 242e124de36Sblymn __CTRACE(__CTRACE_INPUT, 243e124de36Sblymn "inkey: WCASSEMBLING[head(%d), " 244e124de36Sblymn "urrent(%d), tail(%d)]\n", 245fa0b432bSblymn *start, *working, *end); 246fa0b432bSblymn #endif /* DEBUG */ 247070937beSblymn ret = (int)mbrtowc(wc, inbuf + (*working), 1, 248fa0b432bSblymn &_cursesi_screen->sp); 249fa0b432bSblymn #ifdef DEBUG 250e124de36Sblymn __CTRACE(__CTRACE_INPUT, 251e124de36Sblymn "inkey: mbrtowc returns %d, wc(%x)\n", 252fa0b432bSblymn ret, *wc); 253fa0b432bSblymn #endif /* DEBUG */ 254fa0b432bSblymn if (ret == -2) { 25580b412b0Sroy *working = (*working+1) % MAX_CBUF_SIZE; 256fa0b432bSblymn continue; 257fa0b432bSblymn } 258fa0b432bSblymn if ( ret == 0 ) 259fa0b432bSblymn ret = 1; 260fa0b432bSblymn if ( ret == -1 ) { 261fa0b432bSblymn /* return the 1st character we know */ 262fa0b432bSblymn *wc = inbuf[*start]; 263fa0b432bSblymn *working = *start = (*start + 1) % MAX_CBUF_SIZE; 264fa0b432bSblymn #ifdef DEBUG 265e124de36Sblymn __CTRACE(__CTRACE_INPUT, 266e124de36Sblymn "inkey: Invalid wide char(%x) " 267e124de36Sblymn "[head(%d), current(%d), " 268e124de36Sblymn "tail(%d)]\n", 269fa0b432bSblymn *wc, *start, *working, *end); 270fa0b432bSblymn #endif /* DEBUG */ 271fa0b432bSblymn } else { /* > 0 */ 272fa0b432bSblymn /* return the wide character */ 273fa0b432bSblymn *start = *working 274fa0b432bSblymn = (*working + ret)%MAX_CBUF_SIZE; 275fa0b432bSblymn #ifdef DEBUG 276e124de36Sblymn __CTRACE(__CTRACE_INPUT, 277e124de36Sblymn "inkey: Wide char found(%x) " 278e124de36Sblymn "[head(%d), current(%d), " 279e124de36Sblymn "tail(%d)]\n", 280fa0b432bSblymn *wc, *start, *working, *end); 281fa0b432bSblymn #endif /* DEBUG */ 282fa0b432bSblymn } 283fa0b432bSblymn 28480b412b0Sroy if (*start == *end) { 28580b412b0Sroy /* only one char processed */ 2862a9f52daSrin _cursesi_state = wstate = INKEY_NORM; 287fa0b432bSblymn #ifdef DEBUG 288e124de36Sblymn __CTRACE(__CTRACE_INPUT, 289e124de36Sblymn "inkey: WCASSEMBLING=>NORM, " 290e124de36Sblymn "start(%d), current(%d), end(%d)", 291fa0b432bSblymn *start, *working, *end); 292fa0b432bSblymn #endif /* DEBUG */ 293fa0b432bSblymn } else { 29480b412b0Sroy /* otherwise we must have more than 29580b412b0Sroy * one char to backout */ 2962a9f52daSrin _cursesi_state = wstate = INKEY_BACKOUT; 297fa0b432bSblymn #ifdef DEBUG 298e124de36Sblymn __CTRACE(__CTRACE_INPUT, 299e124de36Sblymn "inkey: WCASSEMBLING=>BACKOUT, " 300e124de36Sblymn "start(%d), current(%d), end(%d)", 301fa0b432bSblymn *start, *working, *end); 302fa0b432bSblymn #endif /* DEBUG */ 303fa0b432bSblymn } 304fa0b432bSblymn return OK; 305fa0b432bSblymn } 306fa0b432bSblymn } else { 307fa0b432bSblymn fprintf(stderr, "Inkey wstate screwed - exiting!!!"); 308fa0b432bSblymn exit(2); 309fa0b432bSblymn } 310fa0b432bSblymn 311fa0b432bSblymn /* 312fa0b432bSblymn * Check key has no special meaning and we have not 313fa0b432bSblymn * timed out and the key has not been disabled 314fa0b432bSblymn */ 315fa0b432bSblymn mapping = current->mapping[k]; 316fa0b432bSblymn if (((wstate == INKEY_TIMEOUT) || (mapping < 0)) 317fa0b432bSblymn || ((current->key[mapping]->type 318fa0b432bSblymn == KEYMAP_LEAF) 31980b412b0Sroy && (current->key[mapping]->enable == FALSE))) 32080b412b0Sroy { 3210f41cbdbSwiz /* wide-character specific code */ 322fa0b432bSblymn #ifdef DEBUG 323e124de36Sblymn __CTRACE(__CTRACE_INPUT, 324e124de36Sblymn "inkey: Checking for wide char\n"); 325fa0b432bSblymn #endif /* DEBUG */ 326fa0b432bSblymn mbrtowc( NULL, NULL, 1, &_cursesi_screen->sp ); 327fa0b432bSblymn *working = *start; 328fa0b432bSblymn mlen = *end > *working ? 329fa0b432bSblymn *end - *working : MAX_CBUF_SIZE - *working; 330fa0b432bSblymn if (!mlen) 331fa0b432bSblymn return ERR; 332fa0b432bSblymn #ifdef DEBUG 333e124de36Sblymn __CTRACE(__CTRACE_INPUT, 334e124de36Sblymn "inkey: Check wide char[head(%d), " 335e124de36Sblymn "current(%d), tail(%d), mlen(%ld)]\n", 336e124de36Sblymn *start, *working, *end, (long) mlen); 337fa0b432bSblymn #endif /* DEBUG */ 338070937beSblymn ret = (int)mbrtowc(wc, inbuf + (*working), mlen, 339fa0b432bSblymn &_cursesi_screen->sp); 340fa0b432bSblymn #ifdef DEBUG 341e124de36Sblymn __CTRACE(__CTRACE_INPUT, 342e124de36Sblymn "inkey: mbrtowc returns %d, wc(%x)\n", ret, *wc); 343fa0b432bSblymn #endif /* DEBUG */ 344fa0b432bSblymn if (ret == -2 && *end < *working) { 345fa0b432bSblymn /* second half of a wide character */ 346fa0b432bSblymn *working = 0; 347fa0b432bSblymn mlen = *end; 348fa0b432bSblymn if (mlen) 349070937beSblymn ret = (int)mbrtowc(wc, inbuf, mlen, 350fa0b432bSblymn &_cursesi_screen->sp); 351fa0b432bSblymn } 352fa0b432bSblymn if (ret == -2 && wstate != INKEY_TIMEOUT) { 353070937beSblymn *working = (*working + (int) mlen) 354070937beSblymn % MAX_CBUF_SIZE; 355fa0b432bSblymn wstate = INKEY_WCASSEMBLING; 356fa0b432bSblymn continue; 357fa0b432bSblymn } 358fa0b432bSblymn if (ret == 0) 359fa0b432bSblymn ret = 1; 360fa0b432bSblymn if (ret == -1) { 361fa0b432bSblymn /* return the first key we know about */ 362fa0b432bSblymn *wc = inbuf[*start]; 363fa0b432bSblymn *working = *start 364fa0b432bSblymn = (*start + 1) % MAX_CBUF_SIZE; 365fa0b432bSblymn #ifdef DEBUG 366e124de36Sblymn __CTRACE(__CTRACE_INPUT, 367e124de36Sblymn "inkey: Invalid wide char(%x)[head(%d), " 368e124de36Sblymn "current(%d), tail(%d)]\n", 369fa0b432bSblymn *wc, *start, *working, *end); 370fa0b432bSblymn #endif /* DEBUG */ 371fa0b432bSblymn } else { /* > 0 */ 372fa0b432bSblymn /* return the wide character */ 373fa0b432bSblymn *start = *working 374fa0b432bSblymn = (*working + ret) % MAX_CBUF_SIZE; 375fa0b432bSblymn #ifdef DEBUG 376e124de36Sblymn __CTRACE(__CTRACE_INPUT, 377e124de36Sblymn "inkey: Wide char found(%x)[head(%d), " 378e124de36Sblymn "current(%d), tail(%d)]\n", 379fa0b432bSblymn *wc, *start, *working, *end); 380fa0b432bSblymn #endif /* DEBUG */ 381fa0b432bSblymn } 382fa0b432bSblymn 383fa0b432bSblymn if (*start == *end) { /* only one char processed */ 3842a9f52daSrin _cursesi_state = wstate = INKEY_NORM; 385fa0b432bSblymn #ifdef DEBUG 386e124de36Sblymn __CTRACE(__CTRACE_INPUT, 387e124de36Sblymn "inkey: Empty cbuf=>NORM, " 388e124de36Sblymn "start(%d), current(%d), end(%d)\n", 389fa0b432bSblymn *start, *working, *end); 390fa0b432bSblymn #endif /* DEBUG */ 391fa0b432bSblymn } else { 39280b412b0Sroy /* otherwise we must have more than one 39380b412b0Sroy * char to backout */ 3942a9f52daSrin _cursesi_state = wstate = INKEY_BACKOUT; 395fa0b432bSblymn #ifdef DEBUG 396e124de36Sblymn __CTRACE(__CTRACE_INPUT, 397e124de36Sblymn "inkey: Non-empty cbuf=>BACKOUT, " 398e124de36Sblymn "start(%d), current(%d), end(%d)\n", 399fa0b432bSblymn *start, *working, *end); 400fa0b432bSblymn #endif /* DEBUG */ 401fa0b432bSblymn } 402fa0b432bSblymn return OK; 403fa0b432bSblymn } else { /* must be part of a multikey sequence */ 404fa0b432bSblymn /* check for completed key sequence */ 405fa0b432bSblymn if (current->key[current->mapping[k]]->type 406fa0b432bSblymn == KEYMAP_LEAF) { 407fa0b432bSblymn /* eat the key sequence in cbuf */ 40880b412b0Sroy *start = *working = ( *working + 1 ) 40980b412b0Sroy % MAX_CBUF_SIZE; 410fa0b432bSblymn 411fa0b432bSblymn /* check if inbuf empty now */ 412fa0b432bSblymn #ifdef DEBUG 413e124de36Sblymn __CTRACE(__CTRACE_INPUT, 414e124de36Sblymn "inkey: Key found(%s)\n", 415fa0b432bSblymn key_name(current->key[mapping]->value.symbol)); 416fa0b432bSblymn #endif /* DEBUG */ 417fa0b432bSblymn if (*start == *end) { 418fa0b432bSblymn /* if it is go back to normal */ 4192a9f52daSrin _cursesi_state = wstate = INKEY_NORM; 420fa0b432bSblymn #ifdef DEBUG 421e124de36Sblymn __CTRACE(__CTRACE_INPUT, 422e124de36Sblymn "[inkey]=>NORM, start(%d), " 423e124de36Sblymn "current(%d), end(%d)", 424fa0b432bSblymn *start, *working, *end); 425fa0b432bSblymn #endif /* DEBUG */ 426fa0b432bSblymn } else { 427fa0b432bSblymn /* otherwise go to backout state */ 4282a9f52daSrin _cursesi_state = wstate = INKEY_BACKOUT; 429fa0b432bSblymn #ifdef DEBUG 430e124de36Sblymn __CTRACE(__CTRACE_INPUT, 431e124de36Sblymn "[inkey]=>BACKOUT, start(%d), " 432e124de36Sblymn "current(%d), end(%d)", 433fa0b432bSblymn *start, *working, *end ); 434fa0b432bSblymn #endif /* DEBUG */ 435fa0b432bSblymn } 436fa0b432bSblymn 437fa0b432bSblymn /* return the symbol */ 438fa0b432bSblymn *wc = current->key[mapping]->value.symbol; 439fa0b432bSblymn return KEY_CODE_YES; 440fa0b432bSblymn } else { 441fa0b432bSblymn /* Step to next part of multi-key sequence */ 442fa0b432bSblymn current = current->key[current->mapping[k]]->value.next; 443fa0b432bSblymn } 444fa0b432bSblymn } 445fa0b432bSblymn } 446fa0b432bSblymn } 447fa0b432bSblymn 448fa0b432bSblymn /* 449fa0b432bSblymn * get_wch -- 450fa0b432bSblymn * Read in a wide character from stdscr. 451fa0b432bSblymn */ 452fa0b432bSblymn int 453fa0b432bSblymn get_wch(wint_t *ch) 454fa0b432bSblymn { 455fa0b432bSblymn return wget_wch(stdscr, ch); 456fa0b432bSblymn } 457fa0b432bSblymn 458fa0b432bSblymn /* 459fa0b432bSblymn * mvget_wch -- 460fa0b432bSblymn * Read in a character from stdscr at the given location. 461fa0b432bSblymn */ 462fa0b432bSblymn int 463fa0b432bSblymn mvget_wch(int y, int x, wint_t *ch) 464fa0b432bSblymn { 465fa0b432bSblymn return mvwget_wch(stdscr, y, x, ch); 466fa0b432bSblymn } 467fa0b432bSblymn 468fa0b432bSblymn /* 469fa0b432bSblymn * mvwget_wch -- 470fa0b432bSblymn * Read in a character from stdscr at the given location in the 471fa0b432bSblymn * given window. 472fa0b432bSblymn */ 473fa0b432bSblymn int 474fa0b432bSblymn mvwget_wch(WINDOW *win, int y, int x, wint_t *ch) 475fa0b432bSblymn { 476a5d2c93aSblymn if (wmove(win, y, x) == ERR) 477fa0b432bSblymn return ERR; 478fa0b432bSblymn 479fa0b432bSblymn return wget_wch(win, ch); 480fa0b432bSblymn } 481fa0b432bSblymn 482fa0b432bSblymn /* 483fa0b432bSblymn * wget_wch -- 484fa0b432bSblymn * Read in a wide character from the window. 485fa0b432bSblymn */ 486fa0b432bSblymn int 487fa0b432bSblymn wget_wch(WINDOW *win, wint_t *ch) 488fa0b432bSblymn { 489fa0b432bSblymn int ret, weset; 490fa0b432bSblymn int c; 491fa0b432bSblymn FILE *infd = _cursesi_screen->infd; 492fa0b432bSblymn cchar_t wc; 493fa0b432bSblymn wchar_t inp, ws[2]; 494fa0b432bSblymn 49580b412b0Sroy if (!(win->flags & __SCROLLOK) 49680b412b0Sroy && (win->flags & __FULLWIN) 497fa0b432bSblymn && win->curx == win->maxx - 1 498fa0b432bSblymn && win->cury == win->maxy - 1 499fa0b432bSblymn && __echoit) 50080b412b0Sroy return ERR; 501fa0b432bSblymn 502*d6782af8Suwe if (!(win->flags & __ISPAD) && is_wintouched(win)) 503fa0b432bSblymn wrefresh(win); 504fa0b432bSblymn #ifdef DEBUG 505e124de36Sblymn __CTRACE(__CTRACE_INPUT, "wget_wch: __echoit = %d, " 506e124de36Sblymn "__rawmode = %d, __nl = %d, flags = %#.4x\n", 507fa0b432bSblymn __echoit, __rawmode, _cursesi_screen->nl, win->flags); 508fa0b432bSblymn #endif 5097cc6075bSjdc if (_cursesi_screen->resized) { 5104f781456Sroy resizeterm(LINES, COLS); 5111f380abcSroy _cursesi_screen->resized = 0; 5127cc6075bSjdc *ch = KEY_RESIZE; 5137cc6075bSjdc return KEY_CODE_YES; 5147cc6075bSjdc } 5157cc6075bSjdc if (_cursesi_screen->unget_pos) { 5167cc6075bSjdc #ifdef DEBUG 5177cc6075bSjdc __CTRACE(__CTRACE_INPUT, "wget_wch returning char at %d\n", 5187cc6075bSjdc _cursesi_screen->unget_pos); 5197cc6075bSjdc #endif 5207cc6075bSjdc _cursesi_screen->unget_pos--; 5217cc6075bSjdc *ch = _cursesi_screen->unget_list[_cursesi_screen->unget_pos]; 5227cc6075bSjdc if (__echoit) { 5237cc6075bSjdc ws[0] = *ch, ws[1] = L'\0'; 5247cc6075bSjdc setcchar(&wc, ws, win->wattr, 0, NULL); 5257cc6075bSjdc wadd_wch(win, &wc); 5267cc6075bSjdc } 5277cc6075bSjdc return KEY_CODE_YES; 5287cc6075bSjdc } 529fa0b432bSblymn if (__echoit && !__rawmode) { 530fa0b432bSblymn cbreak(); 531fa0b432bSblymn weset = 1; 532fa0b432bSblymn } else 533fa0b432bSblymn weset = 0; 534fa0b432bSblymn 535fa0b432bSblymn __save_termios(); 536fa0b432bSblymn 537fa0b432bSblymn if (win->flags & __KEYPAD) { 538fa0b432bSblymn switch (win->delay) { 539fa0b432bSblymn case -1: 540fa0b432bSblymn ret = inkey(&inp, 541fa0b432bSblymn win->flags & __NOTIMEOUT ? 0 : 1, 0); 542fa0b432bSblymn break; 543fa0b432bSblymn case 0: 544905b39a9Sdsl if (__nodelay() == ERR) 545fa0b432bSblymn return ERR; 546fa0b432bSblymn ret = inkey(&inp, 0, 0); 547fa0b432bSblymn break; 548fa0b432bSblymn default: 549fa0b432bSblymn ret = inkey(&inp, 550fa0b432bSblymn win->flags & __NOTIMEOUT ? 0 : 1, 551fa0b432bSblymn win->delay); 552fa0b432bSblymn break; 553fa0b432bSblymn } 554fa0b432bSblymn if ( ret == ERR ) 555fa0b432bSblymn return ERR; 556fa0b432bSblymn } else { 5574aeb00ceSroy bool resized; 5584aeb00ceSroy 559fa0b432bSblymn switch (win->delay) { 560fa0b432bSblymn case -1: 561fa0b432bSblymn break; 562fa0b432bSblymn case 0: 563905b39a9Sdsl if (__nodelay() == ERR) 564fa0b432bSblymn return ERR; 565fa0b432bSblymn break; 566fa0b432bSblymn default: 567905b39a9Sdsl if (__timeout(win->delay) == ERR) 568fa0b432bSblymn return ERR; 569fa0b432bSblymn break; 570fa0b432bSblymn } 571fa0b432bSblymn 5724aeb00ceSroy c = __fgetwc_resize(infd, &resized); 5734aeb00ceSroy if (c == WEOF) { 574fa0b432bSblymn clearerr(infd); 575fa0b432bSblymn __restore_termios(); 5764aeb00ceSroy if (resized) { 5778df9a300Srin *ch = KEY_RESIZE; 5788df9a300Srin return KEY_CODE_YES; 5798df9a300Srin } else 580fa0b432bSblymn return ERR; 581fa0b432bSblymn } else { 582fa0b432bSblymn ret = c; 583fa0b432bSblymn inp = c; 584fa0b432bSblymn } 585fa0b432bSblymn } 586fa0b432bSblymn #ifdef DEBUG 587fa0b432bSblymn if (inp > 255) 588fa0b432bSblymn /* we have a key symbol - treat it differently */ 589fa0b432bSblymn /* XXXX perhaps __unctrl should be expanded to include 590fa0b432bSblymn * XXXX the keysyms in the table.... 591fa0b432bSblymn */ 592e124de36Sblymn __CTRACE(__CTRACE_INPUT, "wget_wch assembled keysym 0x%x\n", 593e124de36Sblymn inp); 594fa0b432bSblymn else 595e124de36Sblymn __CTRACE(__CTRACE_INPUT, "wget_wch got '%s'\n", unctrl(inp)); 596fa0b432bSblymn #endif 597fa0b432bSblymn if (win->delay > -1) { 598905b39a9Sdsl if (__delay() == ERR) 599fa0b432bSblymn return ERR; 600fa0b432bSblymn } 601fa0b432bSblymn 602fa0b432bSblymn __restore_termios(); 603fa0b432bSblymn 604fa0b432bSblymn if (__echoit) { 605fa0b432bSblymn if ( ret == KEY_CODE_YES ) { 606fa0b432bSblymn /* handle [DEL], [BS], and [LEFT] */ 607fa0b432bSblymn if ( win->curx && 608fa0b432bSblymn ( inp == KEY_DC || 609fa0b432bSblymn inp == KEY_BACKSPACE || 610fa0b432bSblymn inp == KEY_LEFT )) { 611a5d2c93aSblymn wmove( win, win->cury, win->curx - 1); 612fa0b432bSblymn wdelch( win ); 613fa0b432bSblymn } 614fa0b432bSblymn } else { 615fa0b432bSblymn ws[ 0 ] = inp, ws[ 1 ] = L'\0'; 616fa0b432bSblymn setcchar( &wc, ws, win->wattr, 0, NULL ); 617fa0b432bSblymn wadd_wch( win, &wc ); 618fa0b432bSblymn } 619fa0b432bSblymn } 620fa0b432bSblymn 621fa0b432bSblymn if (weset) 622fa0b432bSblymn nocbreak(); 623fa0b432bSblymn 624fa0b432bSblymn if (_cursesi_screen->nl && inp == 13) 625fa0b432bSblymn inp = 10; 626fa0b432bSblymn 627fa0b432bSblymn *ch = inp; 628fa0b432bSblymn 629fa0b432bSblymn if ( ret == KEY_CODE_YES ) 630fa0b432bSblymn return KEY_CODE_YES; 63180b412b0Sroy return inp < 0 ? ERR : OK; 632fa0b432bSblymn } 633fa0b432bSblymn 634fa0b432bSblymn /* 635fa0b432bSblymn * unget_wch -- 636fa0b432bSblymn * Put the wide character back into the input queue. 637fa0b432bSblymn */ 638fa0b432bSblymn int 639fa0b432bSblymn unget_wch(const wchar_t c) 640fa0b432bSblymn { 6417cc6075bSjdc return __unget((wint_t)c); 642fa0b432bSblymn } 6434aeb00ceSroy 6444aeb00ceSroy /* 6454aeb00ceSroy * __fgetwc_resize -- 6464aeb00ceSroy * Any call to fgetwc(3) should use this function instead. 6474aeb00ceSroy */ 6484aeb00ceSroy static wint_t 6494aeb00ceSroy __fgetwc_resize(FILE *infd, bool *resized) 6504aeb00ceSroy { 6514aeb00ceSroy wint_t c; 6524aeb00ceSroy 6534aeb00ceSroy c = fgetwc(infd); 6544aeb00ceSroy if (c != WEOF) 6554aeb00ceSroy return c; 6564aeb00ceSroy 6574aeb00ceSroy if (!ferror(infd) || errno != EINTR || !_cursesi_screen->resized) 6584aeb00ceSroy return ERR; 6594aeb00ceSroy #ifdef DEBUG 6604aeb00ceSroy __CTRACE(__CTRACE_INPUT, "__fgetwc_resize returning KEY_RESIZE\n"); 6614aeb00ceSroy #endif 6624f781456Sroy resizeterm(LINES, COLS); 6631f380abcSroy _cursesi_screen->resized = 0; 6644aeb00ceSroy *resized = true; 6654aeb00ceSroy return c; 6664aeb00ceSroy } 667