blob: 06c72e3760ddbf5cb9930e05c48ce2e2c4471c8f [file] [log] [blame]
/****************************************************************************
* Copyright 2022 Leonid S. Usov <leonid.s.usov at gmail.com> *
* Copyright 2022 Thomas E. Dickey *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, distribute with modifications, sublicense, and/or sell *
* copies of the Software, and to permit persons to whom the Software is *
* furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included *
* in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************/
/*
* $Id: test_mouse.c,v 1.26 2022/12/04 00:40:11 tom Exp $
*
* Author: Leonid S Usov
*
* Observe mouse events in the raw terminal or parsed ncurses modes
*/
#include <test.priv.h>
#if defined(NCURSES_MOUSE_VERSION) && !defined(_NC_WINDOWS)
static int logoffset = 0;
static int
raw_loop(void)
{
struct termios tty;
struct termios old;
char *xtermcap;
tcgetattr(0, &old);
#if HAVE_CFMAKERAW
cfmakeraw(&tty);
#else
tty = old;
tty.c_iflag &= (unsigned) (~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON));
tty.c_oflag &= (unsigned) (~OPOST);
tty.c_lflag &= (unsigned) (~(ECHO | ECHONL | ICANON | ISIG | IEXTEN));
tty.c_cflag &= (unsigned) (~(CSIZE | PARENB));
tty.c_cflag |= CS8;
tcsetattr(0, TCSANOW, &tty);
#endif
setupterm(NULL, 0, 0);
xtermcap = tigetstr("XM");
if (!VALID_STRING(xtermcap)) {
fprintf(stderr, "couldn't get XM terminfo");
return 1;
}
putp(tparm(xtermcap, 1));
fflush(stdout);
tcsetattr(0, TCSANOW, &tty);
while (1) {
int c = getc(stdin);
const char *pretty;
if (c == -1 || c == '\003') {
break;
} else if (c == '\033') {
printf("\r\n\\E");
} else if ((pretty = unctrl((chtype) c)) != NULL) {
printf("%s", pretty);
} else if (isprint(c)) {
printf("%c", c);
} else {
printf("{%x}", UChar(c));
}
}
putp(tparm(xtermcap, 0));
fflush(stdout);
tcsetattr(0, TCSANOW, &old);
return 0;
}
static void logw(const char *fmt, ...) GCC_PRINTFLIKE(1, 2);
static void
logw(const char *fmt, ...)
{
int row = getcury(stdscr);
va_list args;
va_start(args, fmt);
wmove(stdscr, row++, 0);
vw_printw(stdscr, fmt, args);
va_end(args);
clrtoeol();
row %= (getmaxy(stdscr) - logoffset);
if (row < logoffset) {
row = logoffset;
}
wmove(stdscr, row, 0);
wprintw(stdscr, ">");
clrtoeol();
}
static void
usage(int ok)
{
static const char *msg[] =
{
"Usage: test_mouse [options]"
,""
,"Test mouse events. These examples for $TERM demonstrate xterm"
,"features:"
," xterm"
," xterm-1002"
," xterm-1003"
,""
,USAGE_COMMON
,"Options:"
," -r show raw input stream, injecting a new line before every ESC"
," -i n set mouse interval to n; default is 0 (no double-clicks)"
," -T term use terminal description other than $TERM"
};
unsigned n;
for (n = 0; n < sizeof(msg) / sizeof(char *); ++n) {
fprintf(stderr, "%s\n", msg[n]);
}
ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
/* *INDENT-OFF* */
VERSION_COMMON()
/* *INDENT-ON* */
int
main(int argc, char *argv[])
{
bool rawmode = FALSE;
int interval = 0;
int ch;
MEVENT event;
char *my_environ = NULL;
const char *term_format = "TERM=%s";
while ((ch = getopt(argc, argv, OPTS_COMMON "i:rT:")) != -1) {
switch (ch) {
case 'i':
interval = atoi(optarg);
break;
case 'r':
rawmode = TRUE;
break;
case 'T':
my_environ = malloc(strlen(term_format) + strlen(optarg));
sprintf(my_environ, term_format, optarg);
putenv(my_environ);
break;
case OPTS_VERSION:
show_version(argv);
ExitProgram(EXIT_SUCCESS);
default:
usage(ch == OPTS_USAGE);
/* NOTREACHED */
}
}
if (optind < argc) {
usage(FALSE);
ExitProgram(EXIT_FAILURE);
}
if (rawmode) {
printf("Entering raw mode. Ctrl-c to quit.\n");
return raw_loop();
}
initscr();
noecho();
cbreak(); /* Line buffering disabled; pass everything */
nonl();
keypad(stdscr, TRUE);
/* Get all the mouse events */
mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
mouseinterval(interval);
logw("Ctrl-c to quit");
logw("--------------");
if (my_environ)
logw("%s", my_environ);
logoffset = getcury(stdscr);
while (1) {
int c = getch();
switch (c) {
case KEY_MOUSE:
if (getmouse(&event) == OK) {
unsigned btn;
mmask_t events;
#if NCURSES_MOUSE_VERSION > 1
const unsigned max_btn = 5;
#else
const unsigned max_btn = 4;
#endif
const mmask_t btn_mask = (NCURSES_BUTTON_RELEASED |
NCURSES_BUTTON_PRESSED |
NCURSES_BUTTON_CLICKED |
NCURSES_DOUBLE_CLICKED |
NCURSES_TRIPLE_CLICKED);
bool found = FALSE;
for (btn = 1; btn <= max_btn; btn++) {
events = (mmask_t) (event.bstate
& NCURSES_MOUSE_MASK(btn, btn_mask));
if (events == 0)
continue;
#define ShowQ(btn,name) \
(((event.bstate & NCURSES_MOUSE_MASK(btn, NCURSES_ ## name)) != 0) \
? (" " #name) \
: "")
#define ShowM(name) \
(((event.bstate & NCURSES_MOUSE_MASK(btn, BUTTON_ ## name)) != 0) \
? (" " #name) \
: "")
#define ShowP() \
((event.bstate & REPORT_MOUSE_POSITION) != 0 \
? " position" \
: "")
logw("[%08lX] button %d%s%s%s%s%s%s%s%s%s @ %d, %d",
(unsigned long) events,
btn,
ShowQ(btn, BUTTON_RELEASED),
ShowQ(btn, BUTTON_PRESSED),
ShowQ(btn, BUTTON_CLICKED),
ShowQ(btn, DOUBLE_CLICKED),
ShowQ(btn, TRIPLE_CLICKED),
ShowM(SHIFT),
ShowM(CTRL),
ShowM(ALT),
ShowP(),
event.y, event.x);
found = TRUE;
}
/*
* A position report need not have a button associated with it.
* The modifiers probably are unused.
*/
if (!found && (event.bstate & REPORT_MOUSE_POSITION)) {
logw("[%08lX]%s%s%s%s @ %d, %d",
(unsigned long) events,
ShowM(SHIFT),
ShowM(CTRL),
ShowM(ALT),
ShowP(),
event.y, event.x);
}
}
break;
case '\003':
goto end;
default:
logw("got another char: 0x%x", UChar(c));
}
refresh();
}
end:
endwin();
ExitProgram(EXIT_SUCCESS);
}
#else
int
main(void)
{
printf("This program requires the ncurses library\n");
ExitProgram(EXIT_FAILURE);
}
#endif