mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-11-01 18:30:55 +01:00
24073 (plus tweak): zcurses mouse handling
This commit is contained in:
parent
1e836045b3
commit
a563cd8958
3 changed files with 291 additions and 28 deletions
|
|
@ -1,3 +1,9 @@
|
|||
2007-11-07 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* 24073 (plus tweak to allow "zcurses mouse" with no additional
|
||||
arguments): Doc/Zsh/mod_curses.yo, Src/Modules/curses.c:
|
||||
add zcurses mouse handling.
|
||||
|
||||
2007-11-06 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* 24070: Src/utils.c, Test/A03quoting.ztst,
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ 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) ] [...])
|
||||
xitem(tt(zcurses) tt(bg) var(targetwin) [ var({+/-}attribute) | var(fg_col)tt(/)var(bg_col) | tt(@)var(char) ] [...])
|
||||
xitem(tt(zcurses) tt(scroll) [ tt(on) | tt(off) | {+/-}var(lines) ])
|
||||
xitem(tt(zcurses) tt(input) var(targetwin) [ var(param) [ var(kpparm) ] ])
|
||||
xitem(tt(zcurses) tt(scroll) var(targetwin) [ tt(on) | tt(off) | {+/-}var(lines) ])
|
||||
xitem(tt(zcurses) tt(input) var(targetwin) [ var(param) [ var(kparam) [ var(mparam) ] ] ])
|
||||
xitem(tt(zcurses) tt(mouse) [ tt(delay) var(num) | {+/-}tt(motion) ])
|
||||
item(tt(zcurses) tt(timeout) var(targetwin) var(intval))(
|
||||
Manipulate curses windows. All uses of this command should be
|
||||
bracketed by `tt(zcurses init)' to initialise use of curses, and
|
||||
|
|
@ -129,14 +130,59 @@ 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.
|
||||
|
||||
If both var(param) and var(kparam) 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(kparam). The
|
||||
key names are the macros defined in the tt(curses.h) or tt(ncurses.h)
|
||||
with the prefix `tt(KEY_)' removed; see also the description of the
|
||||
parameter tt(zcurses_keycodes) below. Other keys cause a value to be
|
||||
set in var(param) as before. On a succesful return only one of
|
||||
var(param) or var(kparam) contains a non-empty string; the other is set
|
||||
to an empty string.
|
||||
|
||||
If var(mparam) is also supplied, tt(input) attempts to handle mouse
|
||||
input. This is only available with the ncurses library; mouse handling
|
||||
can be detected by checking for the exit status of `tt(zcurses mouse)' with
|
||||
no arguments. If a mouse
|
||||
button is clicked (or double- or triple-clicked, or pressed or released with
|
||||
a configurable delay from being clicked) then tt(kparam) is set to the string
|
||||
tt(MOUSE), and var(mparam) is set to an array consisting of the
|
||||
following elements:
|
||||
startitem()
|
||||
sitem(-)(An identifier to discriminate different input devices; this
|
||||
is only rarely useful.)
|
||||
sitem(-)(The x, y and z coordinates of the mouse click relative to
|
||||
the full screen, as three elements in that order (i.e. the y coordinate
|
||||
is, unusually, after the x coordinate). The z coordinate is only
|
||||
available for a few unusual input devices and is otherwise set to zero.)
|
||||
sitem(-)(Any events that occurred as separate items; usually
|
||||
there will be just one. An event consists of tt(PRESSED), tt(RELEASED),
|
||||
tt(CLICKED), tt(DOUBLE_CLICKED) or tt(TRIPLE_CLICKED) followed
|
||||
immediately (in the same element) by the number of the button.)
|
||||
sitem(-)(If the shift key was pressed, the string tt(SHIFT).)
|
||||
sitem(-)(If the control key was pressed, the string tt(CTRL).)
|
||||
sitem(-)(If the alt key was pressed, the string tt(ALT).)
|
||||
endsitem()
|
||||
|
||||
Not all mouse events may be passed through to the terminal window;
|
||||
most terminal emulators handle some mouse events themselves. Note
|
||||
that the ncurses manual implies that using input both with and
|
||||
without mouse handling may cause the mouse cursor to appear and
|
||||
disappear.
|
||||
|
||||
The subcommand tt(mouse) can be used to configure the use of the mouse.
|
||||
There is no window argument; mouse options are global.
|
||||
`tt(zcurses mouse)' with no arguments returns status 0 if mouse handling
|
||||
is possible, else status 1. Otherwise, the possible arguments (which
|
||||
may be combined on the same command line) are as follows.
|
||||
tt(delay) var(num) sets the maximum delay in milliseconds between press and
|
||||
release events to be considered as a click; the value 0 disables click
|
||||
resolution, and the default is one sixth of a second. tt(motion) proceeded
|
||||
by an optional `tt(PLUS())' (the default) or tt(-) turns on or off
|
||||
reporting of mouse motion in addition to clicks, presses and releases,
|
||||
which are always reported. However, it appears reports for mouse
|
||||
motion are not currently implemented.
|
||||
|
||||
tt(timeout) specifies a timeout value for input from var(targetwin).
|
||||
If var(intval) is negative, `tt(zcurses input)' waits indefinitely for
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ static struct ttyinfo saved_tty_state;
|
|||
static struct ttyinfo curses_tty_state;
|
||||
static LinkList zcurses_windows;
|
||||
static HashTable zcurses_colorpairs = NULL;
|
||||
static int zcurses_flags;
|
||||
|
||||
#define ZCURSES_EINVALID 1
|
||||
#define ZCURSES_EDEFINED 2
|
||||
|
|
@ -106,6 +107,11 @@ static HashTable zcurses_colorpairs = NULL;
|
|||
static int zc_errno, zc_color_phase=0;
|
||||
static short next_cp=0;
|
||||
|
||||
enum {
|
||||
ZCF_MOUSE_ACTIVE,
|
||||
ZCF_MOUSE_MASK_CHANGED
|
||||
};
|
||||
|
||||
static const struct zcurses_namenumberpair zcurses_attributes[] = {
|
||||
{"blink", A_BLINK},
|
||||
{"bold", A_BOLD},
|
||||
|
|
@ -131,6 +137,70 @@ static const struct zcurses_namenumberpair zcurses_colors[] = {
|
|||
{NULL, 0}
|
||||
};
|
||||
|
||||
#ifdef NCURSES_MOUSE_VERSION
|
||||
enum zcurses_mouse_event_types {
|
||||
ZCME_PRESSED,
|
||||
ZCME_RELEASED,
|
||||
ZCME_CLICKED,
|
||||
ZCME_DOUBLE_CLICKED,
|
||||
ZCME_TRIPLE_CLICKED
|
||||
};
|
||||
|
||||
static const struct zcurses_namenumberpair zcurses_mouse_event_list[] = {
|
||||
{"PRESSED", ZCME_PRESSED},
|
||||
{"RELEASED", ZCME_RELEASED},
|
||||
{"CLICKED", ZCME_CLICKED},
|
||||
{"DOUBLE_CLICKED", ZCME_DOUBLE_CLICKED},
|
||||
{"TRIPLE_CLICKED", ZCME_TRIPLE_CLICKED},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
struct zcurses_mouse_event {
|
||||
int button;
|
||||
int what;
|
||||
mmask_t event;
|
||||
};
|
||||
|
||||
static const struct zcurses_mouse_event zcurses_mouse_map[] = {
|
||||
{ 1, ZCME_PRESSED, BUTTON1_PRESSED },
|
||||
{ 1, ZCME_RELEASED, BUTTON1_RELEASED },
|
||||
{ 1, ZCME_CLICKED, BUTTON1_CLICKED },
|
||||
{ 1, ZCME_DOUBLE_CLICKED, BUTTON1_DOUBLE_CLICKED },
|
||||
{ 1, ZCME_TRIPLE_CLICKED, BUTTON1_TRIPLE_CLICKED },
|
||||
|
||||
{ 2, ZCME_PRESSED, BUTTON2_PRESSED },
|
||||
{ 2, ZCME_RELEASED, BUTTON2_RELEASED },
|
||||
{ 2, ZCME_CLICKED, BUTTON2_CLICKED },
|
||||
{ 2, ZCME_DOUBLE_CLICKED, BUTTON2_DOUBLE_CLICKED },
|
||||
{ 2, ZCME_TRIPLE_CLICKED, BUTTON2_TRIPLE_CLICKED },
|
||||
|
||||
{ 3, ZCME_PRESSED, BUTTON3_PRESSED },
|
||||
{ 3, ZCME_RELEASED, BUTTON3_RELEASED },
|
||||
{ 3, ZCME_CLICKED, BUTTON3_CLICKED },
|
||||
{ 3, ZCME_DOUBLE_CLICKED, BUTTON3_DOUBLE_CLICKED },
|
||||
{ 3, ZCME_TRIPLE_CLICKED, BUTTON3_TRIPLE_CLICKED },
|
||||
|
||||
{ 4, ZCME_PRESSED, BUTTON4_PRESSED },
|
||||
{ 4, ZCME_RELEASED, BUTTON4_RELEASED },
|
||||
{ 4, ZCME_CLICKED, BUTTON4_CLICKED },
|
||||
{ 4, ZCME_DOUBLE_CLICKED, BUTTON4_DOUBLE_CLICKED },
|
||||
{ 4, ZCME_TRIPLE_CLICKED, BUTTON4_TRIPLE_CLICKED },
|
||||
|
||||
#ifdef BUTTON5_PRESSED
|
||||
/* Not defined if only 32 bits available */
|
||||
{ 5, ZCME_PRESSED, BUTTON5_PRESSED },
|
||||
{ 5, ZCME_RELEASED, BUTTON5_RELEASED },
|
||||
{ 5, ZCME_CLICKED, BUTTON5_CLICKED },
|
||||
{ 5, ZCME_DOUBLE_CLICKED, BUTTON5_DOUBLE_CLICKED },
|
||||
{ 5, ZCME_TRIPLE_CLICKED, BUTTON5_TRIPLE_CLICKED },
|
||||
#endif
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
mmask_t zcurses_mouse_mask = ALL_MOUSE_EVENTS;
|
||||
|
||||
#endif
|
||||
|
||||
/* Autogenerated keypad string/number mapping*/
|
||||
#include "curses_keys.h"
|
||||
|
||||
|
|
@ -919,6 +989,7 @@ zccmd_input(const char *nam, char **args)
|
|||
ZCWin w;
|
||||
char *var;
|
||||
int keypadnum = -1;
|
||||
int nargs = arrlen(args);
|
||||
#ifdef HAVE_WGET_WCH
|
||||
int ret;
|
||||
wint_t wi;
|
||||
|
|
@ -936,12 +1007,37 @@ zccmd_input(const char *nam, char **args)
|
|||
|
||||
w = (ZCWin)getdata(node);
|
||||
|
||||
if (args[1] && args[2]) {
|
||||
if (nargs >= 3) {
|
||||
keypad(w->win, TRUE);
|
||||
} else {
|
||||
keypad(w->win, FALSE);
|
||||
}
|
||||
|
||||
if (nargs >= 4) {
|
||||
#ifdef NCURSES_MOUSE_VERSION
|
||||
if (!(zcurses_flags & ZCF_MOUSE_ACTIVE) ||
|
||||
(zcurses_flags & ZCF_MOUSE_MASK_CHANGED)) {
|
||||
if (mousemask(zcurses_mouse_mask, NULL) == ERR) {
|
||||
zwarnnam(nam, "current mouse mode is not supported");
|
||||
return 1;
|
||||
}
|
||||
zcurses_flags = (zcurses_flags & ~ZCF_MOUSE_MASK_CHANGED) |
|
||||
ZCF_MOUSE_ACTIVE;
|
||||
}
|
||||
#else
|
||||
zwarnnam(nam, "mouse events are not supported");
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
#ifdef NCURSES_MOUSE_VERSION
|
||||
else {
|
||||
if (zcurses_flags & ZCF_MOUSE_ACTIVE) {
|
||||
mousemask((mmask_t)0, NULL);
|
||||
zcurses_flags &= ~ZCF_MOUSE_ACTIVE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WGET_WCH
|
||||
switch (wget_wch(w->win, &wi)) {
|
||||
case OK:
|
||||
|
|
@ -988,32 +1084,97 @@ zccmd_input(const char *nam, char **args)
|
|||
var = "REPLY";
|
||||
if (!setsparam(var, ztrdup(instr)))
|
||||
return 1;
|
||||
if (args[1] && args[2]) {
|
||||
if (nargs >= 3) {
|
||||
if (keypadnum > 0) {
|
||||
const struct zcurses_namenumberpair *nnptr;
|
||||
char fbuf[DIGBUFSIZE+1];
|
||||
#ifdef NCURSES_MOUSE_VERSION
|
||||
if (nargs >= 4 && keypadnum == KEY_MOUSE) {
|
||||
MEVENT mevent;
|
||||
char digits[DIGBUFSIZE];
|
||||
LinkList margs;
|
||||
const struct zcurses_mouse_event *zcmmp = zcurses_mouse_map;
|
||||
|
||||
for (nnptr = keypad_names; nnptr->name; nnptr++) {
|
||||
if (keypadnum == nnptr->number) {
|
||||
if (!setsparam(args[2], ztrdup(nnptr->name)))
|
||||
return 1;
|
||||
if (!setsparam(args[2], ztrdup("MOUSE")))
|
||||
return 1;
|
||||
if (getmouse(&mevent) == ERR) {
|
||||
/*
|
||||
* This may happen if the mouse wasn't in
|
||||
* the window, so set the array to empty
|
||||
* but return success.
|
||||
*/
|
||||
setaparam(args[3], mkarray(NULL));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (keypadnum > KEY_F0) {
|
||||
/* assume it's a function key */
|
||||
sprintf(fbuf, "F%d", keypadnum - KEY_F0);
|
||||
margs = newlinklist();
|
||||
sprintf(digits, "%d", (int)mevent.id);
|
||||
addlinknode(margs, dupstring(digits));
|
||||
sprintf(digits, "%d", mevent.x);
|
||||
addlinknode(margs, dupstring(digits));
|
||||
sprintf(digits, "%d", mevent.y);
|
||||
addlinknode(margs, dupstring(digits));
|
||||
sprintf(digits, "%d", mevent.z);
|
||||
addlinknode(margs, dupstring(digits));
|
||||
|
||||
/*
|
||||
* We only expect one event, but it doesn't hurt
|
||||
* to keep testing.
|
||||
*/
|
||||
for (; zcmmp->button; zcmmp++) {
|
||||
if (mevent.bstate & zcmmp->event) {
|
||||
const struct zcurses_namenumberpair *zcmelp =
|
||||
zcurses_mouse_event_list;
|
||||
for (; zcmelp->name; zcmelp++) {
|
||||
if (zcmelp->number == zcmmp->what) {
|
||||
char *evstr = zhalloc(strlen(zcmelp->name)+2);
|
||||
sprintf(evstr, "%s%d", zcmelp->name,
|
||||
zcmmp->button);
|
||||
addlinknode(margs, evstr);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mevent.bstate & BUTTON_SHIFT)
|
||||
addlinknode(margs, "SHIFT");
|
||||
if (mevent.bstate & BUTTON_CTRL)
|
||||
addlinknode(margs, "CTRL");
|
||||
if (mevent.bstate & BUTTON_SHIFT)
|
||||
addlinknode(margs, "ALT");
|
||||
if (!setaparam(args[3], zlinklist2array(margs)));
|
||||
return 1;
|
||||
} else {
|
||||
/* print raw number */
|
||||
sprintf(fbuf, "%d", keypadnum);
|
||||
#endif
|
||||
const struct zcurses_namenumberpair *nnptr;
|
||||
char fbuf[DIGBUFSIZE+1];
|
||||
|
||||
for (nnptr = keypad_names; nnptr->name; nnptr++) {
|
||||
if (keypadnum == nnptr->number) {
|
||||
if (!setsparam(args[2], ztrdup(nnptr->name)))
|
||||
return 1;
|
||||
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);
|
||||
}
|
||||
if (!setsparam(args[2], ztrdup(fbuf)))
|
||||
return 1;
|
||||
#ifdef NCURSES_MOUSE_VERSION
|
||||
}
|
||||
if (!setsparam(args[2], ztrdup(fbuf)))
|
||||
return 1;
|
||||
#endif
|
||||
} else {
|
||||
if (!setsparam(args[2], ztrdup("")))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#ifdef NCURSES_MOUSE_VERSION
|
||||
if (keypadnum != KEY_MOUSE && nargs >= 4)
|
||||
setaparam(args[3], mkarray(NULL));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1057,6 +1218,55 @@ zccmd_timeout(const char *nam, char **args)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
zccmd_mouse(const char *nam, char **args)
|
||||
{
|
||||
#ifdef NCURSES_MOUSE_VERSION
|
||||
int ret = 0;
|
||||
|
||||
for (; *args; args++) {
|
||||
if (!strcmp(*args, "delay")) {
|
||||
char *eptr;
|
||||
zlong delay;
|
||||
|
||||
if (!*++args ||
|
||||
((delay = zstrtol(*args, &eptr, 10)), eptr != NULL)) {
|
||||
zwarnnam(nam, "mouse delay requires an integer argument");
|
||||
return 1;
|
||||
}
|
||||
if (mouseinterval((int)delay) != OK)
|
||||
ret = 1;
|
||||
} else {
|
||||
char *arg = *args;
|
||||
int onoff = 1;
|
||||
if (*arg == '+')
|
||||
arg++;
|
||||
else if (*arg == '-') {
|
||||
arg++;
|
||||
onoff = 0;
|
||||
}
|
||||
if (!strcmp(arg, "motion")) {
|
||||
mmask_t old_mask = zcurses_mouse_mask;
|
||||
if (onoff)
|
||||
zcurses_mouse_mask |= REPORT_MOUSE_POSITION;
|
||||
else
|
||||
zcurses_mouse_mask &= ~REPORT_MOUSE_POSITION;
|
||||
if (old_mask != zcurses_mouse_mask)
|
||||
zcurses_flags |= ZCF_MOUSE_MASK_CHANGED;
|
||||
} else {
|
||||
zwarnnam(nam, "unrecognised mouse command: %s", *arg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
zccmd_position(const char *nam, char **args)
|
||||
{
|
||||
|
|
@ -1141,8 +1351,9 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
|
|||
{"attr", zccmd_attr, 2, -1},
|
||||
{"bg", zccmd_bg, 2, -1},
|
||||
{"scroll", zccmd_scroll, 2, 2},
|
||||
{"input", zccmd_input, 1, 3},
|
||||
{"input", zccmd_input, 1, 4},
|
||||
{"timeout", zccmd_timeout, 2, 2},
|
||||
{"mouse", zccmd_mouse, 0, -1},
|
||||
{"touch", zccmd_touch, 1, -1},
|
||||
{NULL, (zccmd_t)0, 0, 0}
|
||||
};
|
||||
|
|
@ -1165,7 +1376,7 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
|
|||
zwarnnam(nam, "too few arguments for subcommand: %s", args[0]);
|
||||
return 1;
|
||||
} else if (zcsc->maxargs >= 0 && num_args > zcsc->maxargs) {
|
||||
zwarnnam(nam, "too may arguments for subcommand: %s", args[0]);
|
||||
zwarnnam(nam, "too many arguments for subcommand: %s", args[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue