]> ncurses.scripts.mit.edu Git - ncurses.git/blob - test/test_mouse.c
ncurses 6.4 - patch 20240414
[ncurses.git] / test / test_mouse.c
1 /****************************************************************************
2  * Copyright 2022 Leonid S. Usov <leonid.s.usov at gmail.com>               *
3  * Copyright 2022 Thomas E. Dickey                                          *
4  *                                                                          *
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:                 *
12  *                                                                          *
13  * The above copyright notice and this permission notice shall be included  *
14  * in all copies or substantial portions of the Software.                   *
15  *                                                                          *
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  ****************************************************************************/
24 /*
25  * $Id: test_mouse.c,v 1.19 2022/05/15 16:41:20 tom Exp $
26  *
27  * Author: Leonid S Usov
28  *
29  * Observe mouse events in the raw terminal or parsed ncurses modes
30  */
31
32 #include <test.priv.h>
33
34 #if defined(NCURSES_MOUSE_VERSION) && !defined(_NC_WINDOWS)
35
36 static int logoffset = 0;
37
38 static int
39 raw_loop(void)
40 {
41     struct termios tty;
42     struct termios old;
43     char *xtermcap;
44
45     tcgetattr(0, &old);
46     cfmakeraw(&tty);
47
48     setupterm(NULL, 0, 0);
49     xtermcap = tigetstr("XM");
50     if (!VALID_STRING(xtermcap)) {
51         fprintf(stderr, "couldn't get XM terminfo");
52         return 1;
53     }
54
55     putp(tparm(xtermcap, 1));
56     fflush(stdout);
57
58     tcsetattr(0, TCSANOW, &tty);
59
60     while (true) {
61         int c = getc(stdin);
62         const char *pretty;
63
64         if (c == -1 || c == '\003') {
65             break;
66         } else if (c == '\033') {
67             printf("\r\n\\E");
68         } else if ((pretty = unctrl((chtype) c)) != NULL) {
69             printf("%s", pretty);
70         } else if (isprint(c)) {
71             printf("%c", c);
72         } else {
73             printf("{%x}", UChar(c));
74         }
75     }
76
77     putp(tparm(xtermcap, 0));
78     fflush(stdout);
79     tcsetattr(0, TCSANOW, &old);
80     return 0;
81 }
82
83 static void logw(const char *fmt, ...) GCC_PRINTFLIKE(1, 2);
84
85 static void
86 logw(const char *fmt, ...)
87 {
88     int row = getcury(stdscr);
89
90     va_list args;
91     va_start(args, fmt);
92     wmove(stdscr, row++, 0);
93     vw_printw(stdscr, fmt, args);
94     clrtoeol();
95
96     row %= (getmaxy(stdscr) - logoffset);
97     if (row < logoffset) {
98         row = logoffset;
99     }
100
101     wmove(stdscr, row, 0);
102     wprintw(stdscr, ">");
103     clrtoeol();
104 }
105
106 static void
107 usage(void)
108 {
109     static const char *msg[] =
110     {
111         "Usage: test_mouse [options]",
112         "",
113         "Test mouse events.  These examples for $TERM demonstrate xterm"
114         "features:",
115         "    xterm",
116         "    xterm-1002",
117         "    xterm-1003",
118         "",
119         "Options:",
120         " -r       show raw input stream, injecting a new line before every ESC",
121         " -i n     set mouse interval to n; default is 0 (no double-clicks)",
122         " -h       show this message",
123         " -T term  use terminal description other than $TERM"
124     };
125     unsigned n;
126     for (n = 0; n < sizeof(msg) / sizeof(char *); ++n) {
127         fprintf(stderr, "%s\n", msg[n]);
128     }
129 }
130
131 int
132 main(int argc, char *argv[])
133 {
134     bool rawmode = FALSE;
135     int interval = 0;
136     int c;
137     MEVENT event;
138     char *my_environ = NULL;
139     const char *term_format = "TERM=%s";
140
141     while ((c = getopt(argc, argv, "hi:rT:")) != -1) {
142         switch (c) {
143         case 'h':
144             usage();
145             ExitProgram(EXIT_SUCCESS);
146         case 'i':
147             interval = atoi(optarg);
148             break;
149         case 'r':
150             rawmode = TRUE;
151             break;
152         case 'T':
153             my_environ = malloc(strlen(term_format) + strlen(optarg));
154             sprintf(my_environ, term_format, optarg);
155             putenv(my_environ);
156             break;
157         default:
158             usage();
159             ExitProgram(EXIT_FAILURE);
160         }
161     }
162     if (optind < argc) {
163         usage();
164         ExitProgram(EXIT_FAILURE);
165     }
166
167     if (rawmode) {
168         printf("Entering raw mode. Ctrl-c to quit.\n");
169         return raw_loop();
170     }
171
172     initscr();
173     noecho();
174     cbreak();                   /* Line buffering disabled; pass everything */
175     nonl();
176     keypad(stdscr, TRUE);
177
178     /* Get all the mouse events */
179     mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
180     mouseinterval(interval);
181
182     logw("Ctrl-c to quit");
183     logw("--------------");
184     if (my_environ)
185         logw("%s", my_environ);
186     logoffset = getcury(stdscr);
187
188     while (1) {
189         c = getch();
190
191         switch (c) {
192         case KEY_MOUSE:
193             if (getmouse(&event) == OK) {
194                 unsigned btn;
195                 mmask_t events;
196 #if NCURSES_MOUSE_VERSION > 1
197                 const unsigned max_btn = 5;
198 #else
199                 const unsigned max_btn = 4;
200 #endif
201                 const mmask_t btn_mask = (NCURSES_BUTTON_RELEASED |
202                                           NCURSES_BUTTON_PRESSED |
203                                           NCURSES_BUTTON_CLICKED |
204                                           NCURSES_DOUBLE_CLICKED |
205                                           NCURSES_TRIPLE_CLICKED);
206                 bool found = FALSE;
207                 for (btn = 1; btn <= max_btn; btn++) {
208                     events = (mmask_t) (event.bstate
209                                         & NCURSES_MOUSE_MASK(btn, btn_mask));
210                     if (events == 0)
211                         continue;
212 #define ShowQ(btn,name) \
213         (((event.bstate & NCURSES_MOUSE_MASK(btn, NCURSES_ ## name)) != 0) \
214          ? (" " #name) \
215          : "")
216 #define ShowM(name) \
217         (((event.bstate & NCURSES_MOUSE_MASK(btn, BUTTON_ ## name)) != 0) \
218          ? (" " #name) \
219          : "")
220 #define ShowP() \
221          ((event.bstate & REPORT_MOUSE_POSITION) != 0 \
222           ? " position" \
223           : "")
224                     logw("[%08lX] button %d%s%s%s%s%s%s%s%s%s @ %d, %d",
225                          (unsigned long) events,
226                          btn,
227                          ShowQ(btn, BUTTON_RELEASED),
228                          ShowQ(btn, BUTTON_PRESSED),
229                          ShowQ(btn, BUTTON_CLICKED),
230                          ShowQ(btn, DOUBLE_CLICKED),
231                          ShowQ(btn, TRIPLE_CLICKED),
232                          ShowM(SHIFT),
233                          ShowM(CTRL),
234                          ShowM(ALT),
235                          ShowP(),
236                          event.y, event.x);
237                     found = TRUE;
238                 }
239                 /*
240                  * A position report need not have a button associated with it.
241                  * The modifiers probably are unused.
242                  */
243                 if (!found && (event.bstate & REPORT_MOUSE_POSITION)) {
244                     logw("[%08lX]%s%s%s%s @ %d, %d",
245                          (unsigned long) events,
246                          ShowM(SHIFT),
247                          ShowM(CTRL),
248                          ShowM(ALT),
249                          ShowP(),
250                          event.y, event.x);
251                 }
252             }
253             break;
254         case '\003':
255             goto end;
256         default:
257             logw("got another char: 0x%x", UChar(c));
258         }
259         refresh();
260     }
261   end:
262     endwin();
263     ExitProgram(EXIT_SUCCESS);
264 }
265 #else
266 int
267 main(void)
268 {
269     printf("This program requires the ncurses library\n");
270     ExitProgram(EXIT_FAILURE);
271 }
272 #endif