1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-04 10:41:11 +02:00

24024: add zcurses input with keypad handling

This commit is contained in:
Peter Stephenson 2007-10-26 21:59:56 +00:00
parent 26461dcc1b
commit 7f8e229818
6 changed files with 207 additions and 4 deletions

View file

@ -1,3 +1,11 @@
2007-10-26 Peter Stephenson <p.w.stephenson@ntlworld.com>
* 24024: configure.ac, Doc/Zsh/mod_curses.yo,
Src/Modules/curses.c: add "zcurses input" for single character
raw input without echoing. Test for wget_wch for wide
character input. Add handling for keypad() mode by
scanning header.
2007-10-26 Clint Adams <clint@zsh.org>
* 24022: Completion/Debian/Command/_dpkg-repack: completion for

View file

@ -19,7 +19,8 @@ xitem(tt(zcurses) tt(char) var(targetwin) var(character) )
xitem(tt(zcurses) tt(string) var(targetwin) var(string) )
xitem(tt(zcurses) tt(border) var(targetwin) var(border) )(
xitem(tt(zcurses) tt(attr) var(targetwin) [ var({+/-}attribute) | var(fg_col)tt(/)var(bg_col) ] [...])
item(tt(zcurses) tt(scroll) [ tt(on) | tt(off) | {+/-}var(lines) ])(
xitem(tt(zcurses) tt(scroll) [ tt(on) | tt(off) | {+/-}var(lines) ])
item(tt(input) var(targetwin) [ var(param) [ var(kpparm) ] ])(
Manipulate curses windows. All uses of this command should be
bracketed by `tt(zcurses init)' to initialise use of curses, and
`tt(zcurses end)' to end it; omitting `tt(zcurses end)' can cause
@ -44,7 +45,10 @@ var(new_y) and var(new_x).
Outputting characters and strings are achieved by tt(char) and tt(string)
respectively.
To draw a border around window var(targetwin), use tt(border).
To draw a border around window var(targetwin), use tt(border). Note
that the border is not subsequently handled specially: in other words,
the border is simply a set of characters output at the edge of the
window. Hence it can be overwritten, can scroll off the window, etc.
tt(attr) will set var(targetwin)'s attributes or foreground/background
color pair for any successive character output. Each var(attribute)
@ -62,7 +66,19 @@ or negative integer to scroll the window up or down the given number
of lines without changing the current cursor position (which therefore
appears to move in the opposite direction relative to the window).
In the second case, if scrolling is tt(off) it is temporarily turned tt(on)
to allow the window to be scrolled,
to allow the window to be scrolled.
tt(input) reads a single character from the window without echoing
it back. If var(param) is supplied the character is assigned to the
parameter var(param), else it is assigned to the parameter var(REPLY).
If both var(param) and var(kpparam) are supplied, the key is read
in `keypad' mode. In this mode special keys such as function keys
and arrow keys return the name of the key in the parameter var(kpparam).
The key names are the macros defined in the tt(curses.h) or tt(ncurses.h)
with the prefix `tt(KEY_)' removed. Other keys cause a value to be set in
var(param) as before. On a succesful return only one of var(param) or
var(kpparm) contains a non-empty string; the other is set to an empty
string.
)
enditem()

View file

@ -43,6 +43,7 @@
#ifndef MULTIBYTE_SUPPORT
# undef HAVE_SETCCHAR
# undef HAVE_WADDWSTR
# undef HAVE_WGET_WCH
#endif
#ifdef HAVE_SETCCHAR
@ -122,6 +123,9 @@ static const struct zcurses_namenumberpair zcurses_colors[] = {
{NULL, 0}
};
/* Autogenerated keypad string/number mapping*/
#include "curses_keys.h"
static char **
zcurses_pairs_to_array(const struct zcurses_namenumberpair *nnps)
{
@ -335,6 +339,16 @@ zccmd_init(const char *nam, char **args)
zcurses_colorpairs->printnode = NULL;
}
/*
* We use cbreak mode because we don't want line buffering
* on input since we'd just need to loop over characters.
* We use noecho since the manual says that's the right
* thing to do with cbreak.
*
* Turn these on immediately to catch typeahead.
*/
cbreak();
noecho();
gettyinfo(&curses_tty_state);
} else {
settyinfo(&curses_tty_state);
@ -669,6 +683,105 @@ zccmd_scroll(const char *nam, char **args)
}
static int
zccmd_input(const char *nam, char **args)
{
LinkNode node;
ZCWin w;
char *var;
int keypadnum = -1;
#ifdef HAVE_WGET_WCH
int ret;
wint_t wi;
VARARR(char, instr, 2*MB_CUR_MAX+1);
#else
int ci;
instr[3];
#endif
node = zcurses_validate_window(args[0], ZCURSES_USED);
if (node == NULL) {
zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
return 1;
}
w = (ZCWin)getdata(node);
if (args[1] && args[2]) {
keypad(w->win, TRUE);
} else {
keypad(w->win, FALSE);
}
#ifdef HAVE_WGET_WCH
switch (wget_wch(w->win, &wi)) {
case OK:
ret = wctomb(instr, (wchar_t)wi);
if (ret == 0) {
instr[0] = Meta;
instr[1] = '\0' ^ 32;
instr[2] = '\0';
} else {
(void)metafy(instr, ret, META_NOALLOC);
}
break;
case KEY_CODE_YES:
keypadnum = (int)wi;
break;
case ERR:
default:
return 1;
}
#else
ci = wgetch(w->win);
if (ci >= 256) {
keypadnum = ci;
} else {
if (imeta(ci)) {
instr[0] = Meta;
instr[1] = (char)ci ^ 32;
instr[2] = '\0';
} else {
instr[0] = (char)ci;
instr[1] = '\0';
}
}
#endif
if (args[1])
var = args[1];
else
var = "REPLY";
if (!setsparam(var, ztrdup(keypadnum > 0 ? "" : instr)))
return 1;
if (args[2]) {
if (keypadnum > 0) {
const struct zcurses_namenumberpair *nnptr;
char fbuf[DIGBUFSIZE+1];
for (nnptr = keypad_names; nnptr->name; nnptr++) {
if (keypadnum == nnptr->number) {
setsparam(args[2], ztrdup(nnptr->name));
return 0;
}
}
if (keypadnum > KEY_F0) {
/* assume it's a function key */
sprintf(fbuf, "F%d", keypadnum - KEY_F0);
} else {
/* print raw number */
sprintf(fbuf, "%d", keypadnum);
}
setsparam(args[2], ztrdup(fbuf));
} else {
setsparam(args[2], ztrdup(""));
}
}
return 0;
}
/*********************
Main builtin handler
*********************/
@ -693,6 +806,7 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
{"end", zccmd_endwin, 0, 0},
{"attr", zccmd_attr, 2, -1},
{"scroll", zccmd_scroll, 2, 2},
{"input", zccmd_input, 1, 3},
{NULL, (zccmd_t)0, 0, 0}
};

View file

@ -5,3 +5,9 @@ load=no
autobins="zcurses"
objects="curses.o"
:<<\Make
curses.o curses..o: curses_keys.h
curses_keys.h: curses_keys.awk @CURSES_KEYS_H@
$(AWK) -f $(sdir)/curses_keys.awk @CURSES_KEYS_H@ /dev/null >curses_keys.h

View file

@ -0,0 +1,19 @@
BEGIN {nkeydefs = 0}
/^[\t ]*#[\t ]*define[\t _]*KEY_[A-Z0-9_]*[\t ]/ {
keyindex = index($0, "KEY_")
keytail = substr($0, keyindex, 80)
split(keytail, tmp)
keynam = substr(tmp[1], 5, 30)
if (keynam != "MIN" && keynam != "MAX") {
name[nkeydefs++] = keynam
}
}
END {
printf("static const struct zcurses_namenumberpair keypad_names[] = {\n")
for (i = 0; i < 0 + nkeydefs; i++)
printf(" {\"%s\", KEY_%s},\n", name[i], name[i])
printf(" {NULL, 0}\n")
printf("};\n")
}

View file

@ -1134,7 +1134,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
brk sbrk \
pathconf sysconf \
tgetent tigetflag tigetnum tigetstr setupterm initscr \
setcchar waddwstr \
setcchar waddwstr wget_wch \
pcre_compile pcre_study pcre_exec \
nl_langinfo \
erand48 open_memstream \
@ -1354,6 +1354,46 @@ zsh_cv_path_errno_h="$ERRNO_H"
ERRNO_H="$zsh_cv_path_errno_h"
AC_SUBST(ERRNO_H)dnl
dnl Where are curses key definitions located? Need for keypad() mode.
AC_CACHE_CHECK(where curses key definitions are located, zsh_cv_path_curses_keys_h,
[dnl This is an identical trick to errno.h, except we use ncurses.h
dnl if we can.
if test x$ac_cv_header_ncurses_h = xyes; then
echo "#include <ncurses.h>" >nametmp.c
else
if test x$ac_cv_header_curses_h = xyes; then
echo "#include <curses.h>" >nametmp.c
else
echo >nametmp.c
fi
fi
curses_list="`$CPP nametmp.c |
sed -n -e 's/^#line[ ].*\"\(.*\)\"/\1/p' \
-e 's/^#[ 0-9].*\"\(.*\)\"/\1/p' |
sed 's/\\\\\\\\/\//g' |
$AWK '{ if ($1 ~ /\.h/) files[[$1]] = $1 }
END { for (var in files) print var }'`"
rm -f nametmp.c
if x"$curses_list" = x; then
echo Failed
exit 1
fi
for CURSES_TRY_H in $curses_list /dev/null
do
nkeys=`test -f $CURSES_TRY_H && \
$EGREP '#[ ]*define[ ][ ]*KEY_' $CURSES_TRY_H | \
wc -l | sed 's/[ ]//g'`
if test "x$nkeys" != x && test "$nkeys" -ge 10
then
CURSES_KEYS_H=$CURSES_TRY_H
break
fi
done
zsh_cv_path_curses_keys_h="$CURSES_KEYS_H"
])
CURSES_KEYS_H="$zsh_cv_path_curses_keys_h"
AC_SUBST(CURSES_KEYS_H)dnl
dnl -----------------------------------------------------
dnl Look for the file containing the RLIMIT_* definitions
dnl -----------------------------------------------------