1*4aeb00ceSroy /* $NetBSD: get_wch.c,v 1.17 2018/09/27 14:05:26 roy 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*4aeb00ceSroy __RCSID("$NetBSD: get_wch.c,v 1.17 2018/09/27 14:05:26 roy 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 51619b7f0eSjdc #ifdef HAVE_WCHAR 52fa0b432bSblymn static short wstate; /* state of the wcinkey function */ 53619b7f0eSjdc #endif /* HAVE_WCHAR */ 54e124de36Sblymn extern short state; /* storage declared in getch.c */ 55fa0b432bSblymn 56fa0b432bSblymn /* prototypes for private functions */ 57619b7f0eSjdc #ifdef HAVE_WCHAR 58fa0b432bSblymn static int inkey(wchar_t *wc, int to, int delay); 59*4aeb00ceSroy static wint_t __fgetwc_resize(FILE *infd, bool *resized); 60619b7f0eSjdc #endif /* HAVE_WCHAR */ 61fa0b432bSblymn 62619b7f0eSjdc #ifdef HAVE_WCHAR 63fa0b432bSblymn /* 64fa0b432bSblymn * __init_get_wch - initialise all the pointers & structures needed to make 65fa0b432bSblymn * get_wch work in keypad mode. 66fa0b432bSblymn * 67fa0b432bSblymn */ 68fa0b432bSblymn void 69fa0b432bSblymn __init_get_wch(SCREEN *screen) 70fa0b432bSblymn { 71fa0b432bSblymn wstate = INKEY_NORM; 72414be921Sblymn memset(&screen->cbuf, 0, sizeof(screen->cbuf)); 73fa0b432bSblymn screen->cbuf_head = screen->cbuf_tail = screen->cbuf_cur = 0; 74fa0b432bSblymn } 75619b7f0eSjdc #endif /* HAVE_WCHAR */ 76fa0b432bSblymn 77fa0b432bSblymn 78619b7f0eSjdc #ifdef HAVE_WCHAR 79fa0b432bSblymn /* 80fa0b432bSblymn * inkey - do the work to process keyboard input, check for multi-key 81fa0b432bSblymn * sequences and return the appropriate symbol if we get a match. 82fa0b432bSblymn * 83fa0b432bSblymn */ 84619b7f0eSjdc static int 85fa0b432bSblymn inkey(wchar_t *wc, int to, int delay) 86fa0b432bSblymn { 87fa0b432bSblymn wchar_t k = 0; 88fa0b432bSblymn int c, mapping, ret = 0; 89fa0b432bSblymn size_t mlen = 0; 90fa0b432bSblymn keymap_t *current = _cursesi_screen->base_keymap; 91fa0b432bSblymn FILE *infd = _cursesi_screen->infd; 92fa0b432bSblymn int *start = &_cursesi_screen->cbuf_head, 93fa0b432bSblymn *working = &_cursesi_screen->cbuf_cur, 94fa0b432bSblymn *end = &_cursesi_screen->cbuf_tail; 95fa0b432bSblymn char *inbuf = &_cursesi_screen->cbuf[ 0 ]; 96fa0b432bSblymn 977cc6075bSjdc #ifdef DEBUG 987cc6075bSjdc __CTRACE(__CTRACE_INPUT, "inkey (%p, %d, %d)\n", wc, to, delay); 997cc6075bSjdc #endif 100fa0b432bSblymn for (;;) { /* loop until we get a complete key sequence */ 101fa0b432bSblymn if (wstate == INKEY_NORM) { 102fa0b432bSblymn if (delay && __timeout(delay) == ERR) 103fa0b432bSblymn return ERR; 104*4aeb00ceSroy c = __fgetc_resize(infd); 105*4aeb00ceSroy if (c == ERR || c == KEY_RESIZE) { 106fa0b432bSblymn clearerr(infd); 107*4aeb00ceSroy return c; 108fa0b432bSblymn } 109fa0b432bSblymn 110fa0b432bSblymn if (delay && (__notimeout() == ERR)) 111fa0b432bSblymn return ERR; 112fa0b432bSblymn 113fa0b432bSblymn k = (wchar_t)c; 114fa0b432bSblymn #ifdef DEBUG 115e124de36Sblymn __CTRACE(__CTRACE_INPUT, 116e124de36Sblymn "inkey (wstate normal) got '%s'\n", unctrl(k)); 117fa0b432bSblymn #endif 118fa0b432bSblymn 119fa0b432bSblymn inbuf[*end] = k; 120fa0b432bSblymn *end = (*end + 1) % MAX_CBUF_SIZE; 121fa0b432bSblymn *working = *start; 122fa0b432bSblymn wstate = INKEY_ASSEMBLING; /* go to assembling state */ 123fa0b432bSblymn #ifdef DEBUG 124e124de36Sblymn __CTRACE(__CTRACE_INPUT, 125e124de36Sblymn "inkey: NORM=>ASSEMBLING: start(%d), " 126e124de36Sblymn "current(%d), end(%d)\n", *start, *working, *end); 127fa0b432bSblymn #endif /* DEBUG */ 128fa0b432bSblymn } else if (wstate == INKEY_BACKOUT) { 129fa0b432bSblymn k = inbuf[*working]; 130fa0b432bSblymn *working = (*working + 1) % MAX_CBUF_SIZE; 131fa0b432bSblymn if (*working == *end) { /* see if run out of keys */ 132fa0b432bSblymn /* if so, switch to assembling */ 133fa0b432bSblymn wstate = INKEY_ASSEMBLING; 134fa0b432bSblymn #ifdef DEBUG 135e124de36Sblymn __CTRACE(__CTRACE_INPUT, 136e124de36Sblymn "inkey: BACKOUT=>ASSEMBLING, start(%d), " 137e124de36Sblymn "current(%d), end(%d)\n", 138fa0b432bSblymn *start, *working, *end); 139fa0b432bSblymn #endif /* DEBUG */ 140fa0b432bSblymn } 141fa0b432bSblymn } else if (wstate == INKEY_ASSEMBLING) { 142fa0b432bSblymn /* assembling a key sequence */ 143fa0b432bSblymn if (delay) { 144d3b3f557Sroy if (__timeout(to ? (ESCDELAY / 100) : delay) 145fa0b432bSblymn == ERR) 146fa0b432bSblymn return ERR; 147fa0b432bSblymn } else { 148d3b3f557Sroy if (to && (__timeout(ESCDELAY / 100) == ERR)) 149fa0b432bSblymn return ERR; 150fa0b432bSblymn } 151fa0b432bSblymn 152*4aeb00ceSroy c = __fgetc_resize(infd); 153fa0b432bSblymn if (ferror(infd)) { 154fa0b432bSblymn clearerr(infd); 155*4aeb00ceSroy return c; 156fa0b432bSblymn } 157fa0b432bSblymn 158fa0b432bSblymn if ((to || delay) && (__notimeout() == ERR)) 159fa0b432bSblymn return ERR; 160fa0b432bSblymn 161fa0b432bSblymn k = (wchar_t)c; 162fa0b432bSblymn #ifdef DEBUG 163e124de36Sblymn __CTRACE(__CTRACE_INPUT, 164e124de36Sblymn "inkey (wstate assembling) got '%s'\n", unctrl(k)); 165fa0b432bSblymn #endif /* DEBUG */ 166fa0b432bSblymn if (feof(infd)) { /* inter-char T/O, start backout */ 167fa0b432bSblymn clearerr(infd); 168fa0b432bSblymn if (*start == *end) 169fa0b432bSblymn /* no chars in the buffer, restart */ 170fa0b432bSblymn continue; 171fa0b432bSblymn 172fa0b432bSblymn k = inbuf[*start]; 173fa0b432bSblymn wstate = INKEY_TIMEOUT; 174fa0b432bSblymn #ifdef DEBUG 175e124de36Sblymn __CTRACE(__CTRACE_INPUT, 176e124de36Sblymn "inkey: ASSEMBLING=>TIMEOUT, start(%d), " 177e124de36Sblymn "current(%d), end(%d)\n", 178fa0b432bSblymn *start, *working, *end); 179fa0b432bSblymn #endif /* DEBUG */ 180fa0b432bSblymn } else { 181fa0b432bSblymn inbuf[*end] = k; 182fa0b432bSblymn *working = *end; 183fa0b432bSblymn *end = (*end + 1) % MAX_CBUF_SIZE; 184fa0b432bSblymn #ifdef DEBUG 185e124de36Sblymn __CTRACE(__CTRACE_INPUT, 186e124de36Sblymn "inkey: ASSEMBLING: start(%d), " 187e124de36Sblymn "current(%d), end(%d)", 188fa0b432bSblymn *start, *working, *end); 189fa0b432bSblymn #endif /* DEBUG */ 190fa0b432bSblymn } 191fa0b432bSblymn } else if (wstate == INKEY_WCASSEMBLING) { 1920f41cbdbSwiz /* assembling a wide-char sequence */ 193fa0b432bSblymn if (delay) { 194d3b3f557Sroy if (__timeout(to ? (ESCDELAY / 100) : delay) 195fa0b432bSblymn == ERR) 196fa0b432bSblymn return ERR; 197fa0b432bSblymn } else { 198d3b3f557Sroy if (to && (__timeout(ESCDELAY / 100) == ERR)) 199fa0b432bSblymn return ERR; 200fa0b432bSblymn } 201fa0b432bSblymn 202*4aeb00ceSroy c = __fgetc_resize(infd); 203fa0b432bSblymn if (ferror(infd)) { 204fa0b432bSblymn clearerr(infd); 205*4aeb00ceSroy return c; 206fa0b432bSblymn } 207fa0b432bSblymn 208fa0b432bSblymn if ((to || delay) && (__notimeout() == ERR)) 209fa0b432bSblymn return ERR; 210fa0b432bSblymn 211fa0b432bSblymn k = (wchar_t)c; 212fa0b432bSblymn #ifdef DEBUG 213e124de36Sblymn __CTRACE(__CTRACE_INPUT, 214e124de36Sblymn "inkey (wstate wcassembling) got '%s'\n", 215fa0b432bSblymn unctrl(k)); 216fa0b432bSblymn #endif 217fa0b432bSblymn if (feof(infd)) { /* inter-char T/O, start backout */ 218fa0b432bSblymn clearerr(infd); 219fa0b432bSblymn if (*start == *end) 220fa0b432bSblymn /* no chars in the buffer, restart */ 221fa0b432bSblymn continue; 222fa0b432bSblymn 223fa0b432bSblymn *wc = inbuf[*start]; 22480b412b0Sroy *working = *start = (*start +1) % MAX_CBUF_SIZE; 225fa0b432bSblymn if (*start == *end) { 226fa0b432bSblymn state = wstate = INKEY_NORM; 227fa0b432bSblymn #ifdef DEBUG 228e124de36Sblymn __CTRACE(__CTRACE_INPUT, 229e124de36Sblymn "inkey: WCASSEMBLING=>NORM, " 230e124de36Sblymn "start(%d), current(%d), end(%d)", 231fa0b432bSblymn *start, *working, *end); 232fa0b432bSblymn #endif /* DEBUG */ 233fa0b432bSblymn } else { 234fa0b432bSblymn state = wstate = INKEY_BACKOUT; 235fa0b432bSblymn #ifdef DEBUG 236e124de36Sblymn __CTRACE(__CTRACE_INPUT, 237e124de36Sblymn "inkey: WCASSEMBLING=>BACKOUT, " 238e124de36Sblymn "start(%d), current(%d), end(%d)", 239fa0b432bSblymn *start, *working, *end); 240fa0b432bSblymn #endif /* DEBUG */ 241fa0b432bSblymn } 242fa0b432bSblymn return OK; 243fa0b432bSblymn } else { 244fa0b432bSblymn /* assembling wide characters */ 245fa0b432bSblymn inbuf[*end] = k; 246fa0b432bSblymn *working = *end; 247fa0b432bSblymn *end = (*end + 1) % MAX_CBUF_SIZE; 248fa0b432bSblymn #ifdef DEBUG 249e124de36Sblymn __CTRACE(__CTRACE_INPUT, 250e124de36Sblymn "inkey: WCASSEMBLING[head(%d), " 251e124de36Sblymn "urrent(%d), tail(%d)]\n", 252fa0b432bSblymn *start, *working, *end); 253fa0b432bSblymn #endif /* DEBUG */ 254070937beSblymn ret = (int)mbrtowc(wc, inbuf + (*working), 1, 255fa0b432bSblymn &_cursesi_screen->sp); 256fa0b432bSblymn #ifdef DEBUG 257e124de36Sblymn __CTRACE(__CTRACE_INPUT, 258e124de36Sblymn "inkey: mbrtowc returns %d, wc(%x)\n", 259fa0b432bSblymn ret, *wc); 260fa0b432bSblymn #endif /* DEBUG */ 261fa0b432bSblymn if (ret == -2) { 26280b412b0Sroy *working = (*working+1) % MAX_CBUF_SIZE; 263fa0b432bSblymn continue; 264fa0b432bSblymn } 265fa0b432bSblymn if ( ret == 0 ) 266fa0b432bSblymn ret = 1; 267fa0b432bSblymn if ( ret == -1 ) { 268fa0b432bSblymn /* return the 1st character we know */ 269fa0b432bSblymn *wc = inbuf[*start]; 270fa0b432bSblymn *working = *start = (*start + 1) % MAX_CBUF_SIZE; 271fa0b432bSblymn #ifdef DEBUG 272e124de36Sblymn __CTRACE(__CTRACE_INPUT, 273e124de36Sblymn "inkey: Invalid wide char(%x) " 274e124de36Sblymn "[head(%d), current(%d), " 275e124de36Sblymn "tail(%d)]\n", 276fa0b432bSblymn *wc, *start, *working, *end); 277fa0b432bSblymn #endif /* DEBUG */ 278fa0b432bSblymn } else { /* > 0 */ 279fa0b432bSblymn /* return the wide character */ 280fa0b432bSblymn *start = *working 281fa0b432bSblymn = (*working + ret)%MAX_CBUF_SIZE; 282fa0b432bSblymn #ifdef DEBUG 283e124de36Sblymn __CTRACE(__CTRACE_INPUT, 284e124de36Sblymn "inkey: Wide char found(%x) " 285e124de36Sblymn "[head(%d), current(%d), " 286e124de36Sblymn "tail(%d)]\n", 287fa0b432bSblymn *wc, *start, *working, *end); 288fa0b432bSblymn #endif /* DEBUG */ 289fa0b432bSblymn } 290fa0b432bSblymn 29180b412b0Sroy if (*start == *end) { 29280b412b0Sroy /* only one char processed */ 293fa0b432bSblymn state = wstate = INKEY_NORM; 294fa0b432bSblymn #ifdef DEBUG 295e124de36Sblymn __CTRACE(__CTRACE_INPUT, 296e124de36Sblymn "inkey: WCASSEMBLING=>NORM, " 297e124de36Sblymn "start(%d), current(%d), end(%d)", 298fa0b432bSblymn *start, *working, *end); 299fa0b432bSblymn #endif /* DEBUG */ 300fa0b432bSblymn } else { 30180b412b0Sroy /* otherwise we must have more than 30280b412b0Sroy * one char to backout */ 303fa0b432bSblymn state = wstate = INKEY_BACKOUT; 304fa0b432bSblymn #ifdef DEBUG 305e124de36Sblymn __CTRACE(__CTRACE_INPUT, 306e124de36Sblymn "inkey: WCASSEMBLING=>BACKOUT, " 307e124de36Sblymn "start(%d), current(%d), end(%d)", 308fa0b432bSblymn *start, *working, *end); 309fa0b432bSblymn #endif /* DEBUG */ 310fa0b432bSblymn } 311fa0b432bSblymn return OK; 312fa0b432bSblymn } 313fa0b432bSblymn } else { 314fa0b432bSblymn fprintf(stderr, "Inkey wstate screwed - exiting!!!"); 315fa0b432bSblymn exit(2); 316fa0b432bSblymn } 317fa0b432bSblymn 318fa0b432bSblymn /* 319fa0b432bSblymn * Check key has no special meaning and we have not 320fa0b432bSblymn * timed out and the key has not been disabled 321fa0b432bSblymn */ 322fa0b432bSblymn mapping = current->mapping[k]; 323fa0b432bSblymn if (((wstate == INKEY_TIMEOUT) || (mapping < 0)) 324fa0b432bSblymn || ((current->key[mapping]->type 325fa0b432bSblymn == KEYMAP_LEAF) 32680b412b0Sroy && (current->key[mapping]->enable == FALSE))) 32780b412b0Sroy { 3280f41cbdbSwiz /* wide-character specific code */ 329fa0b432bSblymn #ifdef DEBUG 330e124de36Sblymn __CTRACE(__CTRACE_INPUT, 331e124de36Sblymn "inkey: Checking for wide char\n"); 332fa0b432bSblymn #endif /* DEBUG */ 333fa0b432bSblymn mbrtowc( NULL, NULL, 1, &_cursesi_screen->sp ); 334fa0b432bSblymn *working = *start; 335fa0b432bSblymn mlen = *end > *working ? 336fa0b432bSblymn *end - *working : MAX_CBUF_SIZE - *working; 337fa0b432bSblymn if (!mlen) 338fa0b432bSblymn return ERR; 339fa0b432bSblymn #ifdef DEBUG 340e124de36Sblymn __CTRACE(__CTRACE_INPUT, 341e124de36Sblymn "inkey: Check wide char[head(%d), " 342e124de36Sblymn "current(%d), tail(%d), mlen(%ld)]\n", 343e124de36Sblymn *start, *working, *end, (long) mlen); 344fa0b432bSblymn #endif /* DEBUG */ 345070937beSblymn ret = (int)mbrtowc(wc, inbuf + (*working), mlen, 346fa0b432bSblymn &_cursesi_screen->sp); 347fa0b432bSblymn #ifdef DEBUG 348e124de36Sblymn __CTRACE(__CTRACE_INPUT, 349e124de36Sblymn "inkey: mbrtowc returns %d, wc(%x)\n", ret, *wc); 350fa0b432bSblymn #endif /* DEBUG */ 351fa0b432bSblymn if (ret == -2 && *end < *working) { 352fa0b432bSblymn /* second half of a wide character */ 353fa0b432bSblymn *working = 0; 354fa0b432bSblymn mlen = *end; 355fa0b432bSblymn if (mlen) 356070937beSblymn ret = (int)mbrtowc(wc, inbuf, mlen, 357fa0b432bSblymn &_cursesi_screen->sp); 358fa0b432bSblymn } 359fa0b432bSblymn if (ret == -2 && wstate != INKEY_TIMEOUT) { 360070937beSblymn *working = (*working + (int) mlen) 361070937beSblymn % MAX_CBUF_SIZE; 362fa0b432bSblymn wstate = INKEY_WCASSEMBLING; 363fa0b432bSblymn continue; 364fa0b432bSblymn } 365fa0b432bSblymn if (ret == 0) 366fa0b432bSblymn ret = 1; 367fa0b432bSblymn if (ret == -1) { 368fa0b432bSblymn /* return the first key we know about */ 369fa0b432bSblymn *wc = inbuf[*start]; 370fa0b432bSblymn *working = *start 371fa0b432bSblymn = (*start + 1) % MAX_CBUF_SIZE; 372fa0b432bSblymn #ifdef DEBUG 373e124de36Sblymn __CTRACE(__CTRACE_INPUT, 374e124de36Sblymn "inkey: Invalid wide char(%x)[head(%d), " 375e124de36Sblymn "current(%d), tail(%d)]\n", 376fa0b432bSblymn *wc, *start, *working, *end); 377fa0b432bSblymn #endif /* DEBUG */ 378fa0b432bSblymn } else { /* > 0 */ 379fa0b432bSblymn /* return the wide character */ 380fa0b432bSblymn *start = *working 381fa0b432bSblymn = (*working + ret) % MAX_CBUF_SIZE; 382fa0b432bSblymn #ifdef DEBUG 383e124de36Sblymn __CTRACE(__CTRACE_INPUT, 384e124de36Sblymn "inkey: Wide char found(%x)[head(%d), " 385e124de36Sblymn "current(%d), tail(%d)]\n", 386fa0b432bSblymn *wc, *start, *working, *end); 387fa0b432bSblymn #endif /* DEBUG */ 388fa0b432bSblymn } 389fa0b432bSblymn 390fa0b432bSblymn if (*start == *end) { /* only one char processed */ 391fa0b432bSblymn state = wstate = INKEY_NORM; 392fa0b432bSblymn #ifdef DEBUG 393e124de36Sblymn __CTRACE(__CTRACE_INPUT, 394e124de36Sblymn "inkey: Empty cbuf=>NORM, " 395e124de36Sblymn "start(%d), current(%d), end(%d)\n", 396fa0b432bSblymn *start, *working, *end); 397fa0b432bSblymn #endif /* DEBUG */ 398fa0b432bSblymn } else { 39980b412b0Sroy /* otherwise we must have more than one 40080b412b0Sroy * char to backout */ 401fa0b432bSblymn state = wstate = INKEY_BACKOUT; 402fa0b432bSblymn #ifdef DEBUG 403e124de36Sblymn __CTRACE(__CTRACE_INPUT, 404e124de36Sblymn "inkey: Non-empty cbuf=>BACKOUT, " 405e124de36Sblymn "start(%d), current(%d), end(%d)\n", 406fa0b432bSblymn *start, *working, *end); 407fa0b432bSblymn #endif /* DEBUG */ 408fa0b432bSblymn } 409fa0b432bSblymn return OK; 410fa0b432bSblymn } else { /* must be part of a multikey sequence */ 411fa0b432bSblymn /* check for completed key sequence */ 412fa0b432bSblymn if (current->key[current->mapping[k]]->type 413fa0b432bSblymn == KEYMAP_LEAF) { 414fa0b432bSblymn /* eat the key sequence in cbuf */ 41580b412b0Sroy *start = *working = ( *working + 1 ) 41680b412b0Sroy % MAX_CBUF_SIZE; 417fa0b432bSblymn 418fa0b432bSblymn /* check if inbuf empty now */ 419fa0b432bSblymn #ifdef DEBUG 420e124de36Sblymn __CTRACE(__CTRACE_INPUT, 421e124de36Sblymn "inkey: Key found(%s)\n", 422fa0b432bSblymn key_name(current->key[mapping]->value.symbol)); 423fa0b432bSblymn #endif /* DEBUG */ 424fa0b432bSblymn if (*start == *end) { 425fa0b432bSblymn /* if it is go back to normal */ 426fa0b432bSblymn state = wstate = INKEY_NORM; 427fa0b432bSblymn #ifdef DEBUG 428e124de36Sblymn __CTRACE(__CTRACE_INPUT, 429e124de36Sblymn "[inkey]=>NORM, start(%d), " 430e124de36Sblymn "current(%d), end(%d)", 431fa0b432bSblymn *start, *working, *end); 432fa0b432bSblymn #endif /* DEBUG */ 433fa0b432bSblymn } else { 434fa0b432bSblymn /* otherwise go to backout state */ 435fa0b432bSblymn state = wstate = INKEY_BACKOUT; 436fa0b432bSblymn #ifdef DEBUG 437e124de36Sblymn __CTRACE(__CTRACE_INPUT, 438e124de36Sblymn "[inkey]=>BACKOUT, start(%d), " 439e124de36Sblymn "current(%d), end(%d)", 440fa0b432bSblymn *start, *working, *end ); 441fa0b432bSblymn #endif /* DEBUG */ 442fa0b432bSblymn } 443fa0b432bSblymn 444fa0b432bSblymn /* return the symbol */ 445fa0b432bSblymn *wc = current->key[mapping]->value.symbol; 446fa0b432bSblymn return KEY_CODE_YES; 447fa0b432bSblymn } else { 448fa0b432bSblymn /* Step to next part of multi-key sequence */ 449fa0b432bSblymn current = current->key[current->mapping[k]]->value.next; 450fa0b432bSblymn } 451fa0b432bSblymn } 452fa0b432bSblymn } 453fa0b432bSblymn } 454619b7f0eSjdc #endif /* HAVE_WCHAR */ 455fa0b432bSblymn 456fa0b432bSblymn /* 457fa0b432bSblymn * get_wch -- 458fa0b432bSblymn * Read in a wide character from stdscr. 459fa0b432bSblymn */ 460fa0b432bSblymn int 461fa0b432bSblymn get_wch(wint_t *ch) 462fa0b432bSblymn { 463fa0b432bSblymn #ifndef HAVE_WCHAR 464fa0b432bSblymn return ERR; 465fa0b432bSblymn #else 466fa0b432bSblymn return wget_wch(stdscr, ch); 467fa0b432bSblymn #endif /* HAVE_WCHAR */ 468fa0b432bSblymn } 469fa0b432bSblymn 470fa0b432bSblymn /* 471fa0b432bSblymn * mvget_wch -- 472fa0b432bSblymn * Read in a character from stdscr at the given location. 473fa0b432bSblymn */ 474fa0b432bSblymn int 475fa0b432bSblymn mvget_wch(int y, int x, wint_t *ch) 476fa0b432bSblymn { 477fa0b432bSblymn #ifndef HAVE_WCHAR 478fa0b432bSblymn return ERR; 479fa0b432bSblymn #else 480fa0b432bSblymn return mvwget_wch(stdscr, y, x, ch); 481fa0b432bSblymn #endif /* HAVE_WCHAR */ 482fa0b432bSblymn } 483fa0b432bSblymn 484fa0b432bSblymn /* 485fa0b432bSblymn * mvwget_wch -- 486fa0b432bSblymn * Read in a character from stdscr at the given location in the 487fa0b432bSblymn * given window. 488fa0b432bSblymn */ 489fa0b432bSblymn int 490fa0b432bSblymn mvwget_wch(WINDOW *win, int y, int x, wint_t *ch) 491fa0b432bSblymn { 492fa0b432bSblymn #ifndef HAVE_WCHAR 493fa0b432bSblymn return ERR; 494fa0b432bSblymn #else 495fa0b432bSblymn if (wmove(win, y, x) == ERR) 496fa0b432bSblymn return ERR; 497fa0b432bSblymn 498fa0b432bSblymn return wget_wch(win, ch); 499fa0b432bSblymn #endif /* HAVE_WCHAR */ 500fa0b432bSblymn } 501fa0b432bSblymn 502fa0b432bSblymn /* 503fa0b432bSblymn * wget_wch -- 504fa0b432bSblymn * Read in a wide character from the window. 505fa0b432bSblymn */ 506fa0b432bSblymn int 507fa0b432bSblymn wget_wch(WINDOW *win, wint_t *ch) 508fa0b432bSblymn { 509fa0b432bSblymn #ifndef HAVE_WCHAR 510fa0b432bSblymn return ERR; 511fa0b432bSblymn #else 512fa0b432bSblymn int ret, weset; 513fa0b432bSblymn int c; 514fa0b432bSblymn FILE *infd = _cursesi_screen->infd; 515fa0b432bSblymn cchar_t wc; 516fa0b432bSblymn wchar_t inp, ws[2]; 517fa0b432bSblymn 51880b412b0Sroy if (!(win->flags & __SCROLLOK) 51980b412b0Sroy && (win->flags & __FULLWIN) 520fa0b432bSblymn && win->curx == win->maxx - 1 521fa0b432bSblymn && win->cury == win->maxy - 1 522fa0b432bSblymn && __echoit) 52380b412b0Sroy return ERR; 524fa0b432bSblymn 525fa0b432bSblymn if (is_wintouched(win)) 526fa0b432bSblymn wrefresh(win); 527fa0b432bSblymn #ifdef DEBUG 528e124de36Sblymn __CTRACE(__CTRACE_INPUT, "wget_wch: __echoit = %d, " 529e124de36Sblymn "__rawmode = %d, __nl = %d, flags = %#.4x\n", 530fa0b432bSblymn __echoit, __rawmode, _cursesi_screen->nl, win->flags); 531fa0b432bSblymn #endif 5327cc6075bSjdc if (_cursesi_screen->resized) { 5337cc6075bSjdc _cursesi_screen->resized = 0; 5347cc6075bSjdc *ch = KEY_RESIZE; 5357cc6075bSjdc return KEY_CODE_YES; 5367cc6075bSjdc } 5377cc6075bSjdc if (_cursesi_screen->unget_pos) { 5387cc6075bSjdc #ifdef DEBUG 5397cc6075bSjdc __CTRACE(__CTRACE_INPUT, "wget_wch returning char at %d\n", 5407cc6075bSjdc _cursesi_screen->unget_pos); 5417cc6075bSjdc #endif 5427cc6075bSjdc _cursesi_screen->unget_pos--; 5437cc6075bSjdc *ch = _cursesi_screen->unget_list[_cursesi_screen->unget_pos]; 5447cc6075bSjdc if (__echoit) { 5457cc6075bSjdc ws[0] = *ch, ws[1] = L'\0'; 5467cc6075bSjdc setcchar(&wc, ws, win->wattr, 0, NULL); 5477cc6075bSjdc wadd_wch(win, &wc); 5487cc6075bSjdc } 5497cc6075bSjdc return KEY_CODE_YES; 5507cc6075bSjdc } 551fa0b432bSblymn if (__echoit && !__rawmode) { 552fa0b432bSblymn cbreak(); 553fa0b432bSblymn weset = 1; 554fa0b432bSblymn } else 555fa0b432bSblymn weset = 0; 556fa0b432bSblymn 557fa0b432bSblymn __save_termios(); 558fa0b432bSblymn 559fa0b432bSblymn if (win->flags & __KEYPAD) { 560fa0b432bSblymn switch (win->delay) { 561fa0b432bSblymn case -1: 562fa0b432bSblymn ret = inkey(&inp, 563fa0b432bSblymn win->flags & __NOTIMEOUT ? 0 : 1, 0); 564fa0b432bSblymn break; 565fa0b432bSblymn case 0: 566905b39a9Sdsl if (__nodelay() == ERR) 567fa0b432bSblymn return ERR; 568fa0b432bSblymn ret = inkey(&inp, 0, 0); 569fa0b432bSblymn break; 570fa0b432bSblymn default: 571fa0b432bSblymn ret = inkey(&inp, 572fa0b432bSblymn win->flags & __NOTIMEOUT ? 0 : 1, 573fa0b432bSblymn win->delay); 574fa0b432bSblymn break; 575fa0b432bSblymn } 576fa0b432bSblymn if ( ret == ERR ) 577fa0b432bSblymn return ERR; 578fa0b432bSblymn } else { 579*4aeb00ceSroy bool resized; 580*4aeb00ceSroy 581fa0b432bSblymn switch (win->delay) { 582fa0b432bSblymn case -1: 583fa0b432bSblymn break; 584fa0b432bSblymn case 0: 585905b39a9Sdsl if (__nodelay() == ERR) 586fa0b432bSblymn return ERR; 587fa0b432bSblymn break; 588fa0b432bSblymn default: 589905b39a9Sdsl if (__timeout(win->delay) == ERR) 590fa0b432bSblymn return ERR; 591fa0b432bSblymn break; 592fa0b432bSblymn } 593fa0b432bSblymn 594*4aeb00ceSroy c = __fgetwc_resize(infd, &resized); 595*4aeb00ceSroy if (c == WEOF) { 596fa0b432bSblymn clearerr(infd); 597fa0b432bSblymn __restore_termios(); 598*4aeb00ceSroy if (resized) { 5998df9a300Srin *ch = KEY_RESIZE; 6008df9a300Srin return KEY_CODE_YES; 6018df9a300Srin } else 602fa0b432bSblymn return ERR; 603fa0b432bSblymn } else { 604fa0b432bSblymn ret = c; 605fa0b432bSblymn inp = c; 606fa0b432bSblymn } 607fa0b432bSblymn } 608fa0b432bSblymn #ifdef DEBUG 609fa0b432bSblymn if (inp > 255) 610fa0b432bSblymn /* we have a key symbol - treat it differently */ 611fa0b432bSblymn /* XXXX perhaps __unctrl should be expanded to include 612fa0b432bSblymn * XXXX the keysyms in the table.... 613fa0b432bSblymn */ 614e124de36Sblymn __CTRACE(__CTRACE_INPUT, "wget_wch assembled keysym 0x%x\n", 615e124de36Sblymn inp); 616fa0b432bSblymn else 617e124de36Sblymn __CTRACE(__CTRACE_INPUT, "wget_wch got '%s'\n", unctrl(inp)); 618fa0b432bSblymn #endif 619fa0b432bSblymn if (win->delay > -1) { 620905b39a9Sdsl if (__delay() == ERR) 621fa0b432bSblymn return ERR; 622fa0b432bSblymn } 623fa0b432bSblymn 624fa0b432bSblymn __restore_termios(); 625fa0b432bSblymn 626fa0b432bSblymn if (__echoit) { 627fa0b432bSblymn if ( ret == KEY_CODE_YES ) { 628fa0b432bSblymn /* handle [DEL], [BS], and [LEFT] */ 629fa0b432bSblymn if ( win->curx && 630fa0b432bSblymn ( inp == KEY_DC || 631fa0b432bSblymn inp == KEY_BACKSPACE || 632fa0b432bSblymn inp == KEY_LEFT )) { 633fa0b432bSblymn wmove( win, win->cury, win->curx - 1 ); 634fa0b432bSblymn wdelch( win ); 635fa0b432bSblymn } 636fa0b432bSblymn } else { 637fa0b432bSblymn ws[ 0 ] = inp, ws[ 1 ] = L'\0'; 638fa0b432bSblymn setcchar( &wc, ws, win->wattr, 0, NULL ); 639fa0b432bSblymn wadd_wch( win, &wc ); 640fa0b432bSblymn } 641fa0b432bSblymn } 642fa0b432bSblymn 643fa0b432bSblymn if (weset) 644fa0b432bSblymn nocbreak(); 645fa0b432bSblymn 646fa0b432bSblymn if (_cursesi_screen->nl && inp == 13) 647fa0b432bSblymn inp = 10; 648fa0b432bSblymn 649fa0b432bSblymn *ch = inp; 650fa0b432bSblymn 651fa0b432bSblymn if ( ret == KEY_CODE_YES ) 652fa0b432bSblymn return KEY_CODE_YES; 65380b412b0Sroy return inp < 0 ? ERR : OK; 654fa0b432bSblymn #endif /* HAVE_WCHAR */ 655fa0b432bSblymn } 656fa0b432bSblymn 657fa0b432bSblymn /* 658fa0b432bSblymn * unget_wch -- 659fa0b432bSblymn * Put the wide character back into the input queue. 660fa0b432bSblymn */ 661fa0b432bSblymn int 662fa0b432bSblymn unget_wch(const wchar_t c) 663fa0b432bSblymn { 6647cc6075bSjdc return __unget((wint_t)c); 665fa0b432bSblymn } 666*4aeb00ceSroy 667*4aeb00ceSroy #ifdef HAVE_WCHAR 668*4aeb00ceSroy /* 669*4aeb00ceSroy * __fgetwc_resize -- 670*4aeb00ceSroy * Any call to fgetwc(3) should use this function instead. 671*4aeb00ceSroy */ 672*4aeb00ceSroy static wint_t 673*4aeb00ceSroy __fgetwc_resize(FILE *infd, bool *resized) 674*4aeb00ceSroy { 675*4aeb00ceSroy wint_t c; 676*4aeb00ceSroy 677*4aeb00ceSroy c = fgetwc(infd); 678*4aeb00ceSroy if (c != WEOF) 679*4aeb00ceSroy return c; 680*4aeb00ceSroy 681*4aeb00ceSroy if (!ferror(infd) || errno != EINTR || !_cursesi_screen->resized) 682*4aeb00ceSroy return ERR; 683*4aeb00ceSroy #ifdef DEBUG 684*4aeb00ceSroy __CTRACE(__CTRACE_INPUT, "__fgetwc_resize returning KEY_RESIZE\n"); 685*4aeb00ceSroy #endif 686*4aeb00ceSroy _cursesi_screen->resized = 0; 687*4aeb00ceSroy *resized = true; 688*4aeb00ceSroy return c; 689*4aeb00ceSroy } 690*4aeb00ceSroy #endif 691