mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-08 12:01:21 +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>
|
2007-10-26 Clint Adams <clint@zsh.org>
|
||||||
|
|
||||||
* 24022: Completion/Debian/Command/_dpkg-repack: completion for
|
* 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(string) var(targetwin) var(string) )
|
||||||
xitem(tt(zcurses) tt(border) var(targetwin) var(border) )(
|
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) ] [...])
|
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
|
Manipulate curses windows. All uses of this command should be
|
||||||
bracketed by `tt(zcurses init)' to initialise use of curses, and
|
bracketed by `tt(zcurses init)' to initialise use of curses, and
|
||||||
`tt(zcurses end)' to end it; omitting `tt(zcurses end)' can cause
|
`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)
|
Outputting characters and strings are achieved by tt(char) and tt(string)
|
||||||
respectively.
|
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
|
tt(attr) will set var(targetwin)'s attributes or foreground/background
|
||||||
color pair for any successive character output. Each var(attribute)
|
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
|
of lines without changing the current cursor position (which therefore
|
||||||
appears to move in the opposite direction relative to the window).
|
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)
|
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()
|
enditem()
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#ifndef MULTIBYTE_SUPPORT
|
#ifndef MULTIBYTE_SUPPORT
|
||||||
# undef HAVE_SETCCHAR
|
# undef HAVE_SETCCHAR
|
||||||
# undef HAVE_WADDWSTR
|
# undef HAVE_WADDWSTR
|
||||||
|
# undef HAVE_WGET_WCH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SETCCHAR
|
#ifdef HAVE_SETCCHAR
|
||||||
|
@ -122,6 +123,9 @@ static const struct zcurses_namenumberpair zcurses_colors[] = {
|
||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Autogenerated keypad string/number mapping*/
|
||||||
|
#include "curses_keys.h"
|
||||||
|
|
||||||
static char **
|
static char **
|
||||||
zcurses_pairs_to_array(const struct zcurses_namenumberpair *nnps)
|
zcurses_pairs_to_array(const struct zcurses_namenumberpair *nnps)
|
||||||
{
|
{
|
||||||
|
@ -335,6 +339,16 @@ zccmd_init(const char *nam, char **args)
|
||||||
zcurses_colorpairs->printnode = NULL;
|
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);
|
gettyinfo(&curses_tty_state);
|
||||||
} else {
|
} else {
|
||||||
settyinfo(&curses_tty_state);
|
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
|
Main builtin handler
|
||||||
*********************/
|
*********************/
|
||||||
|
@ -693,6 +806,7 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
|
||||||
{"end", zccmd_endwin, 0, 0},
|
{"end", zccmd_endwin, 0, 0},
|
||||||
{"attr", zccmd_attr, 2, -1},
|
{"attr", zccmd_attr, 2, -1},
|
||||||
{"scroll", zccmd_scroll, 2, 2},
|
{"scroll", zccmd_scroll, 2, 2},
|
||||||
|
{"input", zccmd_input, 1, 3},
|
||||||
{NULL, (zccmd_t)0, 0, 0}
|
{NULL, (zccmd_t)0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,3 +5,9 @@ load=no
|
||||||
autobins="zcurses"
|
autobins="zcurses"
|
||||||
|
|
||||||
objects="curses.o"
|
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 \
|
brk sbrk \
|
||||||
pathconf sysconf \
|
pathconf sysconf \
|
||||||
tgetent tigetflag tigetnum tigetstr setupterm initscr \
|
tgetent tigetflag tigetnum tigetstr setupterm initscr \
|
||||||
setcchar waddwstr \
|
setcchar waddwstr wget_wch \
|
||||||
pcre_compile pcre_study pcre_exec \
|
pcre_compile pcre_study pcre_exec \
|
||||||
nl_langinfo \
|
nl_langinfo \
|
||||||
erand48 open_memstream \
|
erand48 open_memstream \
|
||||||
|
@ -1354,6 +1354,46 @@ zsh_cv_path_errno_h="$ERRNO_H"
|
||||||
ERRNO_H="$zsh_cv_path_errno_h"
|
ERRNO_H="$zsh_cv_path_errno_h"
|
||||||
AC_SUBST(ERRNO_H)dnl
|
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 -----------------------------------------------------
|
||||||
dnl Look for the file containing the RLIMIT_* definitions
|
dnl Look for the file containing the RLIMIT_* definitions
|
||||||
dnl -----------------------------------------------------
|
dnl -----------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue