1 /****************************************************************************
2 * Copyright 2022-2023,2024 Thomas E. Dickey *
3 * Copyright 2022 Leonid S. Usov <leonid.s.usov at gmail.com> *
5 * Permission is hereby granted, free of charge, to any person obtaining a *
6 * copy of this software and associated documentation files (the *
7 * "Software"), to deal in the Software without restriction, including *
8 * without limitation the rights to use, copy, modify, merge, publish, *
9 * distribute, distribute with modifications, sublicense, and/or sell *
10 * copies of the Software, and to permit persons to whom the Software is *
11 * furnished to do so, subject to the following conditions: *
13 * The above copyright notice and this permission notice shall be included *
14 * in all copies or substantial portions of the Software. *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 ****************************************************************************/
25 * $Id: test_mouse.c,v 1.29 2024/02/10 14:39:40 tom Exp $
27 * Author: Leonid S Usov
29 * Observe mouse events in the raw terminal or parsed ncurses modes
32 #include <test.priv.h>
34 #if defined(NCURSES_MOUSE_VERSION) && !defined(_NC_WINDOWS)
36 static int logoffset = 0;
50 tty.c_iflag &= (unsigned) (~(IGNBRK | BRKINT | PARMRK | ISTRIP
51 | INLCR | IGNCR | ICRNL | IXON));
52 tty.c_oflag &= (unsigned) (~OPOST);
53 tty.c_lflag &= (unsigned) (~(ECHO | ECHONL | ICANON | ISIG | IEXTEN));
54 tty.c_cflag &= (unsigned) (~(CSIZE | PARENB));
56 tcsetattr(0, TCSANOW, &tty);
59 setupterm(NULL, 0, 0);
60 xtermcap = tigetstr("XM");
61 if (!VALID_STRING(xtermcap)) {
62 fprintf(stderr, "couldn't get XM terminfo");
66 putp(tgoto(xtermcap, 1, 1));
69 tcsetattr(0, TCSANOW, &tty);
75 if (c == -1 || c == '\003') {
77 } else if (c == '\033') {
79 } else if ((pretty = unctrl((chtype) c)) != NULL) {
81 } else if (isprint(c)) {
84 printf("{%x}", UChar(c));
88 putp(tgoto(xtermcap, 0, 0));
90 tcsetattr(0, TCSANOW, &old);
94 static void logw(const char *fmt, ...) GCC_PRINTFLIKE(1, 2);
97 logw(const char *fmt, ...)
99 int row = getcury(stdscr);
103 wmove(stdscr, row++, 0);
104 vw_printw(stdscr, fmt, args);
109 row %= (getmaxy(stdscr) - logoffset);
110 if (row < logoffset) {
114 wmove(stdscr, row, 0);
115 wprintw(stdscr, ">");
122 static const char *msg[] =
124 "Usage: test_mouse [options]"
126 ,"Test mouse events. These examples for $TERM demonstrate xterm"
134 ," -r show raw input stream, injecting a new line before every ESC"
135 ," -i n set mouse interval to n; default is 0 (no double-clicks)"
136 ," -T term use terminal description other than $TERM"
139 for (n = 0; n < sizeof(msg) / sizeof(char *); ++n) {
140 fprintf(stderr, "%s\n", msg[n]);
142 ExitProgram(ok ? EXIT_SUCCESS : EXIT_FAILURE);
149 main(int argc, char *argv[])
151 bool rawmode = FALSE;
156 char *my_environ = NULL;
157 const char *term_format = "TERM=%s";
159 while ((ch = getopt(argc, argv, OPTS_COMMON "i:rT:")) != -1) {
162 interval = atoi(optarg);
168 my_len = strlen(term_format) + strlen(optarg) + 1;
169 my_environ = malloc(my_len);
170 if (my_environ != NULL) {
171 _nc_SPRINTF(my_environ, _nc_SLIMIT(my_len) term_format, optarg);
177 ExitProgram(EXIT_SUCCESS);
179 usage(ch == OPTS_USAGE);
185 ExitProgram(EXIT_FAILURE);
189 printf("Entering raw mode. Ctrl-c to quit.\n");
195 cbreak(); /* Line buffering disabled; pass everything */
197 keypad(stdscr, TRUE);
199 /* Get all the mouse events */
200 mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
201 mouseinterval(interval);
203 logw("Ctrl-c to quit");
204 logw("--------------");
206 logw("%s", my_environ);
207 logoffset = getcury(stdscr);
214 if (getmouse(&event) == OK) {
217 #if NCURSES_MOUSE_VERSION > 1
218 const unsigned max_btn = 5;
220 const unsigned max_btn = 4;
222 const mmask_t btn_mask = (NCURSES_BUTTON_RELEASED |
223 NCURSES_BUTTON_PRESSED |
224 NCURSES_BUTTON_CLICKED |
225 NCURSES_DOUBLE_CLICKED |
226 NCURSES_TRIPLE_CLICKED);
228 for (btn = 1; btn <= max_btn; btn++) {
229 events = (mmask_t) (event.bstate
230 & NCURSES_MOUSE_MASK(btn, btn_mask));
233 #define ShowQ(btn,name) \
234 (((event.bstate & NCURSES_MOUSE_MASK(btn, NCURSES_ ## name)) != 0) \
237 #define ShowM(name) \
238 (((event.bstate & NCURSES_MOUSE_MASK(btn, BUTTON_ ## name)) != 0) \
242 ((event.bstate & REPORT_MOUSE_POSITION) != 0 \
245 logw("[%08lX] button %d%s%s%s%s%s%s%s%s%s @ %d, %d",
246 (unsigned long) events,
248 ShowQ(btn, BUTTON_RELEASED),
249 ShowQ(btn, BUTTON_PRESSED),
250 ShowQ(btn, BUTTON_CLICKED),
251 ShowQ(btn, DOUBLE_CLICKED),
252 ShowQ(btn, TRIPLE_CLICKED),
261 * A position report need not have a button associated with it.
262 * The modifiers probably are unused.
264 if (!found && (event.bstate & REPORT_MOUSE_POSITION)) {
265 logw("[%08lX]%s%s%s%s @ %d, %d",
266 (unsigned long) events,
278 logw("got another char: 0x%x", UChar(c));
284 ExitProgram(EXIT_SUCCESS);
290 printf("This program requires the ncurses library\n");
291 ExitProgram(EXIT_FAILURE);