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:
parent
26461dcc1b
commit
7f8e229818
6 changed files with 207 additions and 4 deletions
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
19
Src/Modules/curses_keys.awk
Normal file
19
Src/Modules/curses_keys.awk
Normal 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")
|
||||
}
|
42
configure.ac
42
configure.ac
|
@ -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 -----------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue