1 |
|
|
/* $OpenBSD: lib_mouse.c,v 1.14 2010/01/12 23:22:06 nicm Exp $ */ |
2 |
|
|
|
3 |
|
|
/**************************************************************************** |
4 |
|
|
* Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * |
5 |
|
|
* * |
6 |
|
|
* Permission is hereby granted, free of charge, to any person obtaining a * |
7 |
|
|
* copy of this software and associated documentation files (the * |
8 |
|
|
* "Software"), to deal in the Software without restriction, including * |
9 |
|
|
* without limitation the rights to use, copy, modify, merge, publish, * |
10 |
|
|
* distribute, distribute with modifications, sublicense, and/or sell * |
11 |
|
|
* copies of the Software, and to permit persons to whom the Software is * |
12 |
|
|
* furnished to do so, subject to the following conditions: * |
13 |
|
|
* * |
14 |
|
|
* The above copyright notice and this permission notice shall be included * |
15 |
|
|
* in all copies or substantial portions of the Software. * |
16 |
|
|
* * |
17 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * |
18 |
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * |
19 |
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * |
20 |
|
|
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * |
21 |
|
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * |
22 |
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * |
23 |
|
|
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. * |
24 |
|
|
* * |
25 |
|
|
* Except as contained in this notice, the name(s) of the above copyright * |
26 |
|
|
* holders shall not be used in advertising or otherwise to promote the * |
27 |
|
|
* sale, use or other dealings in this Software without prior written * |
28 |
|
|
* authorization. * |
29 |
|
|
****************************************************************************/ |
30 |
|
|
|
31 |
|
|
/**************************************************************************** |
32 |
|
|
* Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * |
33 |
|
|
* and: Eric S. Raymond <esr@snark.thyrsus.com> * |
34 |
|
|
* and: Thomas E. Dickey 1996-on * |
35 |
|
|
****************************************************************************/ |
36 |
|
|
|
37 |
|
|
/* |
38 |
|
|
* This module is intended to encapsulate ncurses's interface to pointing |
39 |
|
|
* devices. |
40 |
|
|
* |
41 |
|
|
* The primary method used is xterm's internal mouse-tracking facility. |
42 |
|
|
* Additional methods depend on the platform: |
43 |
|
|
* Alessandro Rubini's GPM server (Linux) |
44 |
|
|
* sysmouse (FreeBSD) |
45 |
|
|
* special-purpose mouse interface for OS/2 EMX. |
46 |
|
|
* |
47 |
|
|
* Notes for implementors of new mouse-interface methods: |
48 |
|
|
* |
49 |
|
|
* The code is logically split into a lower level that accepts event reports |
50 |
|
|
* in a device-dependent format and an upper level that parses mouse gestures |
51 |
|
|
* and filters events. The mediating data structure is a circular queue of |
52 |
|
|
* MEVENT structures. |
53 |
|
|
* |
54 |
|
|
* Functionally, the lower level's job is to pick up primitive events and |
55 |
|
|
* put them on the circular queue. This can happen in one of two ways: |
56 |
|
|
* either (a) _nc_mouse_event() detects a series of incoming mouse reports |
57 |
|
|
* and queues them, or (b) code in lib_getch.c detects the kmous prefix in |
58 |
|
|
* the keyboard input stream and calls _nc_mouse_inline to queue up a series |
59 |
|
|
* of adjacent mouse reports. |
60 |
|
|
* |
61 |
|
|
* In either case, _nc_mouse_parse() should be called after the series is |
62 |
|
|
* accepted to parse the digested mouse reports (low-level MEVENTs) into |
63 |
|
|
* a gesture (a high-level or composite MEVENT). |
64 |
|
|
* |
65 |
|
|
* Don't be too shy about adding new event types or modifiers, if you can find |
66 |
|
|
* room for them in the 32-bit mask. The API is written so that users get |
67 |
|
|
* feedback on which theoretical event types they won't see when they call |
68 |
|
|
* mousemask. There's one bit per button (the RESERVED_EVENT bit) not being |
69 |
|
|
* used yet, and a couple of bits open at the high end. |
70 |
|
|
*/ |
71 |
|
|
|
72 |
|
|
#ifdef __EMX__ |
73 |
|
|
# include <io.h> |
74 |
|
|
# define INCL_DOS |
75 |
|
|
# define INCL_VIO |
76 |
|
|
# define INCL_KBD |
77 |
|
|
# define INCL_MOU |
78 |
|
|
# define INCL_DOSPROCESS |
79 |
|
|
# include <os2.h> /* Need to include before the others */ |
80 |
|
|
#endif |
81 |
|
|
|
82 |
|
|
#include <curses.priv.h> |
83 |
|
|
|
84 |
|
|
MODULE_ID("$Id: lib_mouse.c,v 1.14 2010/01/12 23:22:06 nicm Exp $") |
85 |
|
|
|
86 |
|
|
#include <term.h> |
87 |
|
|
#include <tic.h> |
88 |
|
|
|
89 |
|
|
#if USE_GPM_SUPPORT |
90 |
|
|
#include <linux/keyboard.h> /* defines KG_* macros */ |
91 |
|
|
|
92 |
|
|
#ifdef HAVE_LIBDL |
93 |
|
|
/* use dynamic loader to avoid linkage dependency */ |
94 |
|
|
#include <dlfcn.h> |
95 |
|
|
|
96 |
|
|
#ifdef RTLD_NOW |
97 |
|
|
#define my_RTLD RTLD_NOW |
98 |
|
|
#else |
99 |
|
|
#ifdef RTLD_LAZY |
100 |
|
|
#define my_RTLD RTLD_LAZY |
101 |
|
|
#else |
102 |
|
|
make an error |
103 |
|
|
#endif |
104 |
|
|
#endif /* RTLD_NOW */ |
105 |
|
|
#endif /* HAVE_LIBDL */ |
106 |
|
|
|
107 |
|
|
#endif /* USE_GPM_SUPPORT */ |
108 |
|
|
|
109 |
|
|
#if USE_SYSMOUSE |
110 |
|
|
#undef buttons /* symbol conflict in consio.h */ |
111 |
|
|
#undef mouse_info /* symbol conflict in consio.h */ |
112 |
|
|
#include <osreldate.h> |
113 |
|
|
#if (__FreeBSD_version >= 400017) |
114 |
|
|
#include <sys/consio.h> |
115 |
|
|
#include <sys/fbio.h> |
116 |
|
|
#else |
117 |
|
|
#include <machine/console.h> |
118 |
|
|
#endif |
119 |
|
|
#endif /* use_SYSMOUSE */ |
120 |
|
|
|
121 |
|
|
#define MY_TRACE TRACE_ICALLS|TRACE_IEVENT |
122 |
|
|
|
123 |
|
|
#define MASK_RELEASE(x) NCURSES_MOUSE_MASK(x, 001) |
124 |
|
|
#define MASK_PRESS(x) NCURSES_MOUSE_MASK(x, 002) |
125 |
|
|
#define MASK_CLICK(x) NCURSES_MOUSE_MASK(x, 004) |
126 |
|
|
#define MASK_DOUBLE_CLICK(x) NCURSES_MOUSE_MASK(x, 010) |
127 |
|
|
#define MASK_TRIPLE_CLICK(x) NCURSES_MOUSE_MASK(x, 020) |
128 |
|
|
#define MASK_RESERVED_EVENT(x) NCURSES_MOUSE_MASK(x, 040) |
129 |
|
|
|
130 |
|
|
#if NCURSES_MOUSE_VERSION == 1 |
131 |
|
|
#define BUTTON_CLICKED (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED | BUTTON4_CLICKED) |
132 |
|
|
#define BUTTON_PRESSED (BUTTON1_PRESSED | BUTTON2_PRESSED | BUTTON3_PRESSED | BUTTON4_PRESSED) |
133 |
|
|
#define BUTTON_RELEASED (BUTTON1_RELEASED | BUTTON2_RELEASED | BUTTON3_RELEASED | BUTTON4_RELEASED) |
134 |
|
|
#define BUTTON_DOUBLE_CLICKED (BUTTON1_DOUBLE_CLICKED | BUTTON2_DOUBLE_CLICKED | BUTTON3_DOUBLE_CLICKED | BUTTON4_DOUBLE_CLICKED) |
135 |
|
|
#define BUTTON_TRIPLE_CLICKED (BUTTON1_TRIPLE_CLICKED | BUTTON2_TRIPLE_CLICKED | BUTTON3_TRIPLE_CLICKED | BUTTON4_TRIPLE_CLICKED) |
136 |
|
|
#define MAX_BUTTONS 4 |
137 |
|
|
#else |
138 |
|
|
#define BUTTON_CLICKED (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED | BUTTON4_CLICKED | BUTTON5_CLICKED) |
139 |
|
|
#define BUTTON_PRESSED (BUTTON1_PRESSED | BUTTON2_PRESSED | BUTTON3_PRESSED | BUTTON4_PRESSED | BUTTON5_PRESSED) |
140 |
|
|
#define BUTTON_RELEASED (BUTTON1_RELEASED | BUTTON2_RELEASED | BUTTON3_RELEASED | BUTTON4_RELEASED | BUTTON5_RELEASED) |
141 |
|
|
#define BUTTON_DOUBLE_CLICKED (BUTTON1_DOUBLE_CLICKED | BUTTON2_DOUBLE_CLICKED | BUTTON3_DOUBLE_CLICKED | BUTTON4_DOUBLE_CLICKED | BUTTON5_DOUBLE_CLICKED) |
142 |
|
|
#define BUTTON_TRIPLE_CLICKED (BUTTON1_TRIPLE_CLICKED | BUTTON2_TRIPLE_CLICKED | BUTTON3_TRIPLE_CLICKED | BUTTON4_TRIPLE_CLICKED | BUTTON5_TRIPLE_CLICKED) |
143 |
|
|
#define MAX_BUTTONS 5 |
144 |
|
|
#endif |
145 |
|
|
|
146 |
|
|
#define INVALID_EVENT -1 |
147 |
|
|
#define NORMAL_EVENT 0 |
148 |
|
|
|
149 |
|
|
#if USE_GPM_SUPPORT |
150 |
|
|
|
151 |
|
|
#ifndef LIBGPM_SONAME |
152 |
|
|
#define LIBGPM_SONAME "libgpm.so" |
153 |
|
|
#endif |
154 |
|
|
|
155 |
|
|
#define GET_DLSYM(name) (my_##name = (TYPE_##name) dlsym(SP->_dlopen_gpm, #name)) |
156 |
|
|
|
157 |
|
|
#endif /* USE_GPM_SUPPORT */ |
158 |
|
|
|
159 |
|
|
static bool _nc_mouse_parse(SCREEN *, int); |
160 |
|
|
static void _nc_mouse_resume(SCREEN *); |
161 |
|
|
static void _nc_mouse_wrap(SCREEN *); |
162 |
|
|
|
163 |
|
|
/* maintain a circular list of mouse events */ |
164 |
|
|
|
165 |
|
|
#define FirstEV(sp) ((sp)->_mouse_events) |
166 |
|
|
#define LastEV(sp) ((sp)->_mouse_events + EV_MAX - 1) |
167 |
|
|
|
168 |
|
|
#undef NEXT |
169 |
|
|
#define NEXT(ep) ((ep >= LastEV(sp)) \ |
170 |
|
|
? FirstEV(sp) \ |
171 |
|
|
: ep + 1) |
172 |
|
|
|
173 |
|
|
#undef PREV |
174 |
|
|
#define PREV(ep) ((ep <= FirstEV(sp)) \ |
175 |
|
|
? LastEV(sp) \ |
176 |
|
|
: ep - 1) |
177 |
|
|
|
178 |
|
|
#define IndexEV(sp, ep) (ep - FirstEV(sp)) |
179 |
|
|
|
180 |
|
|
#define RunParams(sp, eventp, runp) \ |
181 |
|
|
(long) IndexEV(sp, runp), \ |
182 |
|
|
(long) (IndexEV(sp, eventp) + (EV_MAX - 1)) % EV_MAX |
183 |
|
|
|
184 |
|
|
#ifdef TRACE |
185 |
|
|
static void |
186 |
|
|
_trace_slot(SCREEN *sp, const char *tag) |
187 |
|
|
{ |
188 |
|
|
MEVENT *ep; |
189 |
|
|
|
190 |
|
|
_tracef(tag); |
191 |
|
|
|
192 |
|
|
for (ep = FirstEV(sp); ep <= LastEV(sp); ep++) |
193 |
|
|
_tracef("mouse event queue slot %ld = %s", |
194 |
|
|
(long) IndexEV(sp, ep), |
195 |
|
|
_nc_tracemouse(sp, ep)); |
196 |
|
|
} |
197 |
|
|
#endif |
198 |
|
|
|
199 |
|
|
#if USE_EMX_MOUSE |
200 |
|
|
|
201 |
|
|
# define TOP_ROW 0 |
202 |
|
|
# define LEFT_COL 0 |
203 |
|
|
|
204 |
|
|
# define M_FD(sp) sp->_mouse_fd |
205 |
|
|
|
206 |
|
|
static void |
207 |
|
|
write_event(SCREEN *sp, int down, int button, int x, int y) |
208 |
|
|
{ |
209 |
|
|
char buf[6]; |
210 |
|
|
unsigned long ignore; |
211 |
|
|
|
212 |
|
|
strncpy(buf, key_mouse, 3); /* should be "\033[M" */ |
213 |
|
|
buf[3] = ' ' + (button - 1) + (down ? 0 : 0x40); |
214 |
|
|
buf[4] = ' ' + x - LEFT_COL + 1; |
215 |
|
|
buf[5] = ' ' + y - TOP_ROW + 1; |
216 |
|
|
DosWrite(sp->_emxmouse_wfd, buf, 6, &ignore); |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
static void |
220 |
|
|
mouse_server(unsigned long param) |
221 |
|
|
{ |
222 |
|
|
SCREEN *sp = (SCREEN *) param; |
223 |
|
|
unsigned short fWait = MOU_WAIT; |
224 |
|
|
/* NOPTRRECT mourt = { 0,0,24,79 }; */ |
225 |
|
|
MOUEVENTINFO mouev; |
226 |
|
|
HMOU hmou; |
227 |
|
|
unsigned short mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN; |
228 |
|
|
int nbuttons = 3; |
229 |
|
|
int oldstate = 0; |
230 |
|
|
char err[80]; |
231 |
|
|
unsigned long rc; |
232 |
|
|
|
233 |
|
|
/* open the handle for the mouse */ |
234 |
|
|
if (MouOpen(NULL, &hmou) == 0) { |
235 |
|
|
rc = MouSetEventMask(&mask, hmou); |
236 |
|
|
if (rc) { /* retry with 2 buttons */ |
237 |
|
|
mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN; |
238 |
|
|
rc = MouSetEventMask(&mask, hmou); |
239 |
|
|
nbuttons = 2; |
240 |
|
|
} |
241 |
|
|
if (rc == 0 && MouDrawPtr(hmou) == 0) { |
242 |
|
|
for (;;) { |
243 |
|
|
/* sit and wait on the event queue */ |
244 |
|
|
rc = MouReadEventQue(&mouev, &fWait, hmou); |
245 |
|
|
if (rc) { |
246 |
|
|
snprintf(err, sizeof(err), "Error reading mouse queue, rc=%lu.\r\n", rc); |
247 |
|
|
break; |
248 |
|
|
} |
249 |
|
|
if (!sp->_emxmouse_activated) |
250 |
|
|
goto finish; |
251 |
|
|
|
252 |
|
|
/* |
253 |
|
|
* OS/2 numbers a 3-button mouse inconsistently from other |
254 |
|
|
* platforms: |
255 |
|
|
* 1 = left |
256 |
|
|
* 2 = right |
257 |
|
|
* 3 = middle. |
258 |
|
|
*/ |
259 |
|
|
if ((mouev.fs ^ oldstate) & MOUSE_BN1_DOWN) |
260 |
|
|
write_event(sp, mouev.fs & MOUSE_BN1_DOWN, |
261 |
|
|
sp->_emxmouse_buttons[1], mouev.col, mouev.row); |
262 |
|
|
if ((mouev.fs ^ oldstate) & MOUSE_BN2_DOWN) |
263 |
|
|
write_event(sp, mouev.fs & MOUSE_BN2_DOWN, |
264 |
|
|
sp->_emxmouse_buttons[3], mouev.col, mouev.row); |
265 |
|
|
if ((mouev.fs ^ oldstate) & MOUSE_BN3_DOWN) |
266 |
|
|
write_event(sp, mouev.fs & MOUSE_BN3_DOWN, |
267 |
|
|
sp->_emxmouse_buttons[2], mouev.col, mouev.row); |
268 |
|
|
|
269 |
|
|
finish: |
270 |
|
|
oldstate = mouev.fs; |
271 |
|
|
} |
272 |
|
|
} else |
273 |
|
|
snprintf(err, sizeof(err), "Error setting event mask, buttons=%d, rc=%lu.\r\n", |
274 |
|
|
nbuttons, rc); |
275 |
|
|
|
276 |
|
|
DosWrite(2, err, strlen(err), &rc); |
277 |
|
|
MouClose(hmou); |
278 |
|
|
} |
279 |
|
|
DosExit(EXIT_THREAD, 0L); |
280 |
|
|
} |
281 |
|
|
|
282 |
|
|
#endif /* USE_EMX_MOUSE */ |
283 |
|
|
|
284 |
|
|
#if USE_SYSMOUSE |
285 |
|
|
static void |
286 |
|
|
sysmouse_server(SCREEN *sp) |
287 |
|
|
{ |
288 |
|
|
struct mouse_info the_mouse; |
289 |
|
|
MEVENT *work; |
290 |
|
|
|
291 |
|
|
the_mouse.operation = MOUSE_GETINFO; |
292 |
|
|
if (sp != 0 |
293 |
|
|
&& sp->_mouse_fd >= 0 |
294 |
|
|
&& sp->_sysmouse_tail < FIFO_SIZE |
295 |
|
|
&& ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) { |
296 |
|
|
|
297 |
|
|
if (sp->_sysmouse_head > sp->_sysmouse_tail) { |
298 |
|
|
sp->_sysmouse_tail = 0; |
299 |
|
|
sp->_sysmouse_head = 0; |
300 |
|
|
} |
301 |
|
|
work = &(sp->_sysmouse_fifo[sp->_sysmouse_tail]); |
302 |
|
|
memset(work, 0, sizeof(*work)); |
303 |
|
|
work->id = NORMAL_EVENT; /* there's only one mouse... */ |
304 |
|
|
|
305 |
|
|
sp->_sysmouse_old_buttons = sp->_sysmouse_new_buttons; |
306 |
|
|
sp->_sysmouse_new_buttons = the_mouse.u.data.buttons & 0x7; |
307 |
|
|
|
308 |
|
|
if (sp->_sysmouse_new_buttons) { |
309 |
|
|
if (sp->_sysmouse_new_buttons & 1) |
310 |
|
|
work->bstate |= BUTTON1_PRESSED; |
311 |
|
|
if (sp->_sysmouse_new_buttons & 2) |
312 |
|
|
work->bstate |= BUTTON2_PRESSED; |
313 |
|
|
if (sp->_sysmouse_new_buttons & 4) |
314 |
|
|
work->bstate |= BUTTON3_PRESSED; |
315 |
|
|
} else { |
316 |
|
|
if (sp->_sysmouse_old_buttons & 1) |
317 |
|
|
work->bstate |= BUTTON1_RELEASED; |
318 |
|
|
if (sp->_sysmouse_old_buttons & 2) |
319 |
|
|
work->bstate |= BUTTON2_RELEASED; |
320 |
|
|
if (sp->_sysmouse_old_buttons & 4) |
321 |
|
|
work->bstate |= BUTTON3_RELEASED; |
322 |
|
|
} |
323 |
|
|
|
324 |
|
|
/* for cosmetic bug in syscons.c on FreeBSD 3.[34] */ |
325 |
|
|
the_mouse.operation = MOUSE_HIDE; |
326 |
|
|
ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse); |
327 |
|
|
the_mouse.operation = MOUSE_SHOW; |
328 |
|
|
ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse); |
329 |
|
|
|
330 |
|
|
/* |
331 |
|
|
* We're only interested if the button is pressed or released. |
332 |
|
|
* FIXME: implement continuous event-tracking. |
333 |
|
|
*/ |
334 |
|
|
if (sp->_sysmouse_new_buttons != sp->_sysmouse_old_buttons) { |
335 |
|
|
sp->_sysmouse_tail += 1; |
336 |
|
|
} |
337 |
|
|
work->x = the_mouse.u.data.x / sp->_sysmouse_char_width; |
338 |
|
|
work->y = the_mouse.u.data.y / sp->_sysmouse_char_height; |
339 |
|
|
} |
340 |
|
|
} |
341 |
|
|
|
342 |
|
|
static void |
343 |
|
|
handle_sysmouse(int sig GCC_UNUSED) |
344 |
|
|
{ |
345 |
|
|
sysmouse_server(SP); |
346 |
|
|
} |
347 |
|
|
#endif /* USE_SYSMOUSE */ |
348 |
|
|
|
349 |
|
|
static void |
350 |
|
|
init_xterm_mouse(SCREEN *sp) |
351 |
|
|
{ |
352 |
|
|
sp->_mouse_type = M_XTERM; |
353 |
|
|
sp->_mouse_xtermcap = tigetstr("XM"); |
354 |
|
|
if (!VALID_STRING(sp->_mouse_xtermcap)) |
355 |
|
|
sp->_mouse_xtermcap = "\033[?1000%?%p1%{1}%=%th%el%;"; |
356 |
|
|
} |
357 |
|
|
|
358 |
|
|
static void |
359 |
|
|
enable_xterm_mouse(SCREEN *sp, int enable) |
360 |
|
|
{ |
361 |
|
|
#if USE_EMX_MOUSE |
362 |
|
|
sp->_emxmouse_activated = enable; |
363 |
|
|
#else |
364 |
|
|
putp(TPARM_1(sp->_mouse_xtermcap, enable)); |
365 |
|
|
#endif |
366 |
|
|
sp->_mouse_active = enable; |
367 |
|
|
} |
368 |
|
|
|
369 |
|
|
#if USE_GPM_SUPPORT |
370 |
|
|
static bool |
371 |
|
|
allow_gpm_mouse(void) |
372 |
|
|
{ |
373 |
|
|
bool result = FALSE; |
374 |
|
|
|
375 |
|
|
/* GPM does printf's without checking if stdout is a terminal */ |
376 |
|
|
if (isatty(fileno(stdout))) { |
377 |
|
|
char *list = getenv("NCURSES_GPM_TERMS"); |
378 |
|
|
char *env = getenv("TERM"); |
379 |
|
|
if (list != 0) { |
380 |
|
|
if (env != 0) { |
381 |
|
|
result = _nc_name_match(list, env, "|:"); |
382 |
|
|
} |
383 |
|
|
} else { |
384 |
|
|
/* GPM checks the beginning of the $TERM variable to decide if it |
385 |
|
|
* should pass xterm events through. There is no real advantage in |
386 |
|
|
* allowing GPM to do this. Recent versions relax that check, and |
387 |
|
|
* pretend that GPM can work with any terminal having the kmous |
388 |
|
|
* capability. Perhaps that works for someone. If so, they can |
389 |
|
|
* set the environment variable (above). |
390 |
|
|
*/ |
391 |
|
|
if (env != 0 && strstr(env, "linux") != 0) { |
392 |
|
|
result = TRUE; |
393 |
|
|
} |
394 |
|
|
} |
395 |
|
|
} |
396 |
|
|
return result; |
397 |
|
|
} |
398 |
|
|
|
399 |
|
|
#ifdef HAVE_LIBDL |
400 |
|
|
static void |
401 |
|
|
unload_gpm_library(SCREEN *sp) |
402 |
|
|
{ |
403 |
|
|
if (SP->_dlopen_gpm != 0) { |
404 |
|
|
T(("unload GPM library")); |
405 |
|
|
sp->_mouse_gpm_loaded = FALSE; |
406 |
|
|
sp->_mouse_fd = -1; |
407 |
|
|
dlclose(sp->_dlopen_gpm); |
408 |
|
|
sp->_dlopen_gpm = 0; |
409 |
|
|
} |
410 |
|
|
} |
411 |
|
|
|
412 |
|
|
static void |
413 |
|
|
load_gpm_library(SCREEN *sp) |
414 |
|
|
{ |
415 |
|
|
sp->_mouse_gpm_found = FALSE; |
416 |
|
|
if ((sp->_dlopen_gpm = dlopen(LIBGPM_SONAME, my_RTLD)) != 0) { |
417 |
|
|
if (GET_DLSYM(gpm_fd) == 0 || |
418 |
|
|
GET_DLSYM(Gpm_Open) == 0 || |
419 |
|
|
GET_DLSYM(Gpm_Close) == 0 || |
420 |
|
|
GET_DLSYM(Gpm_GetEvent) == 0) { |
421 |
|
|
T(("GPM initialization failed: %s", dlerror())); |
422 |
|
|
unload_gpm_library(sp); |
423 |
|
|
} else { |
424 |
|
|
sp->_mouse_gpm_found = TRUE; |
425 |
|
|
sp->_mouse_gpm_loaded = TRUE; |
426 |
|
|
} |
427 |
|
|
} |
428 |
|
|
} |
429 |
|
|
#endif |
430 |
|
|
|
431 |
|
|
static bool |
432 |
|
|
enable_gpm_mouse(SCREEN *sp, bool enable) |
433 |
|
|
{ |
434 |
|
|
bool result; |
435 |
|
|
|
436 |
|
|
T((T_CALLED("enable_gpm_mouse(%d)"), enable)); |
437 |
|
|
|
438 |
|
|
if (enable && !sp->_mouse_active) { |
439 |
|
|
#ifdef HAVE_LIBDL |
440 |
|
|
if (sp->_mouse_gpm_found && !sp->_mouse_gpm_loaded) { |
441 |
|
|
load_gpm_library(sp); |
442 |
|
|
} |
443 |
|
|
#endif |
444 |
|
|
if (sp->_mouse_gpm_loaded) { |
445 |
|
|
/* GPM: initialize connection to gpm server */ |
446 |
|
|
sp->_mouse_gpm_connect.eventMask = GPM_DOWN | GPM_UP; |
447 |
|
|
sp->_mouse_gpm_connect.defaultMask = |
448 |
|
|
(unsigned short) (~(sp->_mouse_gpm_connect.eventMask | GPM_HARD)); |
449 |
|
|
sp->_mouse_gpm_connect.minMod = 0; |
450 |
|
|
sp->_mouse_gpm_connect.maxMod = |
451 |
|
|
(unsigned short) (~((1 << KG_SHIFT) | |
452 |
|
|
(1 << KG_SHIFTL) | |
453 |
|
|
(1 << KG_SHIFTR))); |
454 |
|
|
/* |
455 |
|
|
* Note: GPM hardcodes \E[?1001s and \E[?1000h during its open. |
456 |
|
|
* The former is recognized by wscons (SunOS), and the latter by |
457 |
|
|
* xterm. Those will not show up in ncurses' traces. |
458 |
|
|
*/ |
459 |
|
|
result = (my_Gpm_Open(&sp->_mouse_gpm_connect, 0) >= 0); |
460 |
|
|
} else { |
461 |
|
|
result = FALSE; |
462 |
|
|
} |
463 |
|
|
sp->_mouse_active = result; |
464 |
|
|
T(("GPM open %s", result ? "succeeded" : "failed")); |
465 |
|
|
} else { |
466 |
|
|
if (!enable && sp->_mouse_active) { |
467 |
|
|
/* GPM: close connection to gpm server */ |
468 |
|
|
my_Gpm_Close(); |
469 |
|
|
sp->_mouse_active = FALSE; |
470 |
|
|
T(("GPM closed")); |
471 |
|
|
} |
472 |
|
|
result = enable; |
473 |
|
|
} |
474 |
|
|
#ifdef HAVE_LIBDL |
475 |
|
|
if (!result) { |
476 |
|
|
unload_gpm_library(sp); |
477 |
|
|
} |
478 |
|
|
#endif |
479 |
|
|
returnBool(result); |
480 |
|
|
} |
481 |
|
|
#endif /* USE_GPM_SUPPORT */ |
482 |
|
|
|
483 |
|
|
#define xterm_kmous "\033[M" |
484 |
|
|
|
485 |
|
|
static void |
486 |
|
|
initialize_mousetype(SCREEN *sp) |
487 |
|
|
{ |
488 |
|
|
T((T_CALLED("initialize_mousetype()"))); |
489 |
|
|
|
490 |
|
|
/* Try gpm first, because gpm may be configured to run in xterm */ |
491 |
|
|
#if USE_GPM_SUPPORT |
492 |
|
|
if (allow_gpm_mouse()) { |
493 |
|
|
if (!sp->_mouse_gpm_loaded) { |
494 |
|
|
#ifdef HAVE_LIBDL |
495 |
|
|
load_gpm_library(sp); |
496 |
|
|
#else /* !HAVE_LIBDL */ |
497 |
|
|
sp->_mouse_gpm_found = TRUE; |
498 |
|
|
sp->_mouse_gpm_loaded = TRUE; |
499 |
|
|
#endif |
500 |
|
|
} |
501 |
|
|
|
502 |
|
|
/* |
503 |
|
|
* The gpm_fd file-descriptor may be negative (xterm). So we have to |
504 |
|
|
* maintain our notion of whether the mouse connection is active |
505 |
|
|
* without testing the file-descriptor. |
506 |
|
|
*/ |
507 |
|
|
if (sp->_mouse_gpm_found && enable_gpm_mouse(sp, TRUE)) { |
508 |
|
|
sp->_mouse_type = M_GPM; |
509 |
|
|
sp->_mouse_fd = *(my_gpm_fd); |
510 |
|
|
T(("GPM mouse_fd %d", sp->_mouse_fd)); |
511 |
|
|
returnVoid; |
512 |
|
|
} |
513 |
|
|
} |
514 |
|
|
#endif /* USE_GPM_SUPPORT */ |
515 |
|
|
|
516 |
|
|
/* OS/2 VIO */ |
517 |
|
|
#if USE_EMX_MOUSE |
518 |
|
|
if (!sp->_emxmouse_thread |
519 |
|
|
&& strstr(cur_term->type.term_names, "xterm") == 0 |
520 |
|
|
&& key_mouse) { |
521 |
|
|
int handles[2]; |
522 |
|
|
|
523 |
|
|
if (pipe(handles) < 0) { |
524 |
|
|
perror("mouse pipe error"); |
525 |
|
|
returnVoid; |
526 |
|
|
} else { |
527 |
|
|
int rc; |
528 |
|
|
|
529 |
|
|
if (!sp->_emxmouse_buttons[0]) { |
530 |
|
|
char *s = getenv("MOUSE_BUTTONS_123"); |
531 |
|
|
|
532 |
|
|
sp->_emxmouse_buttons[0] = 1; |
533 |
|
|
if (s && strlen(s) >= 3) { |
534 |
|
|
sp->_emxmouse_buttons[1] = s[0] - '0'; |
535 |
|
|
sp->_emxmouse_buttons[2] = s[1] - '0'; |
536 |
|
|
sp->_emxmouse_buttons[3] = s[2] - '0'; |
537 |
|
|
} else { |
538 |
|
|
sp->_emxmouse_buttons[1] = 1; |
539 |
|
|
sp->_emxmouse_buttons[2] = 3; |
540 |
|
|
sp->_emxmouse_buttons[3] = 2; |
541 |
|
|
} |
542 |
|
|
} |
543 |
|
|
sp->_emxmouse_wfd = handles[1]; |
544 |
|
|
M_FD(sp) = handles[0]; |
545 |
|
|
/* Needed? */ |
546 |
|
|
setmode(handles[0], O_BINARY); |
547 |
|
|
setmode(handles[1], O_BINARY); |
548 |
|
|
/* Do not use CRT functions, we may single-threaded. */ |
549 |
|
|
rc = DosCreateThread((unsigned long *) &sp->_emxmouse_thread, |
550 |
|
|
mouse_server, (long) sp, 0, 8192); |
551 |
|
|
if (rc) { |
552 |
|
|
printf("mouse thread error %d=%#x", rc, rc); |
553 |
|
|
} else { |
554 |
|
|
sp->_mouse_type = M_XTERM; |
555 |
|
|
} |
556 |
|
|
returnVoid; |
557 |
|
|
} |
558 |
|
|
} |
559 |
|
|
#endif /* USE_EMX_MOUSE */ |
560 |
|
|
|
561 |
|
|
#if USE_SYSMOUSE |
562 |
|
|
{ |
563 |
|
|
struct mouse_info the_mouse; |
564 |
|
|
char *the_device = 0; |
565 |
|
|
|
566 |
|
|
if (isatty(sp->_ifd)) |
567 |
|
|
the_device = ttyname(sp->_ifd); |
568 |
|
|
if (the_device == 0) |
569 |
|
|
the_device = "/dev/tty"; |
570 |
|
|
|
571 |
|
|
sp->_mouse_fd = open(the_device, O_RDWR); |
572 |
|
|
|
573 |
|
|
if (sp->_mouse_fd >= 0) { |
574 |
|
|
/* |
575 |
|
|
* sysmouse does not have a usable user interface for obtaining |
576 |
|
|
* mouse events. The logical way to proceed (reading data on a |
577 |
|
|
* stream) only works if one opens the device as root. Even in |
578 |
|
|
* that mode, careful examination shows we lose events |
579 |
|
|
* occasionally. The interface provided for user programs is to |
580 |
|
|
* establish a signal handler. really. |
581 |
|
|
* |
582 |
|
|
* Take over SIGUSR2 for this purpose since SIGUSR1 is more |
583 |
|
|
* likely to be used by an application. getch() will have to |
584 |
|
|
* handle the misleading EINTR's. |
585 |
|
|
*/ |
586 |
|
|
signal(SIGUSR2, SIG_IGN); |
587 |
|
|
the_mouse.operation = MOUSE_MODE; |
588 |
|
|
the_mouse.u.mode.mode = 0; |
589 |
|
|
the_mouse.u.mode.signal = SIGUSR2; |
590 |
|
|
if (ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) { |
591 |
|
|
signal(SIGUSR2, handle_sysmouse); |
592 |
|
|
the_mouse.operation = MOUSE_SHOW; |
593 |
|
|
ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse); |
594 |
|
|
|
595 |
|
|
#if defined(FBIO_MODEINFO) || defined(CONS_MODEINFO) /* FreeBSD > 2.x */ |
596 |
|
|
{ |
597 |
|
|
#ifndef FBIO_GETMODE /* FreeBSD 3.x */ |
598 |
|
|
#define FBIO_GETMODE CONS_GET |
599 |
|
|
#define FBIO_MODEINFO CONS_MODEINFO |
600 |
|
|
#endif /* FBIO_GETMODE */ |
601 |
|
|
video_info_t the_video; |
602 |
|
|
|
603 |
|
|
if (ioctl(sp->_mouse_fd, |
604 |
|
|
FBIO_GETMODE, |
605 |
|
|
&the_video.vi_mode) != -1 |
606 |
|
|
&& ioctl(sp->_mouse_fd, |
607 |
|
|
FBIO_MODEINFO, |
608 |
|
|
&the_video) != -1) { |
609 |
|
|
sp->_sysmouse_char_width = the_video.vi_cwidth; |
610 |
|
|
sp->_sysmouse_char_height = the_video.vi_cheight; |
611 |
|
|
} |
612 |
|
|
} |
613 |
|
|
#endif /* defined(FBIO_MODEINFO) || defined(CONS_MODEINFO) */ |
614 |
|
|
|
615 |
|
|
if (sp->_sysmouse_char_width <= 0) |
616 |
|
|
sp->_sysmouse_char_width = 8; |
617 |
|
|
if (sp->_sysmouse_char_height <= 0) |
618 |
|
|
sp->_sysmouse_char_height = 16; |
619 |
|
|
sp->_mouse_type = M_SYSMOUSE; |
620 |
|
|
returnVoid; |
621 |
|
|
} |
622 |
|
|
} |
623 |
|
|
} |
624 |
|
|
#endif /* USE_SYSMOUSE */ |
625 |
|
|
|
626 |
|
|
/* we know how to recognize mouse events under "xterm" */ |
627 |
|
|
if (key_mouse != 0) { |
628 |
|
|
if (!strcmp(key_mouse, xterm_kmous) |
629 |
|
|
|| strstr(cur_term->type.term_names, "xterm") != 0) { |
630 |
|
|
init_xterm_mouse(sp); |
631 |
|
|
} |
632 |
|
|
} else if (strstr(cur_term->type.term_names, "xterm") != 0) { |
633 |
|
|
if (_nc_add_to_try(&(sp->_keytry), xterm_kmous, KEY_MOUSE) == OK) |
634 |
|
|
init_xterm_mouse(sp); |
635 |
|
|
} |
636 |
|
|
returnVoid; |
637 |
|
|
} |
638 |
|
|
|
639 |
|
|
static bool |
640 |
|
|
_nc_mouse_init(SCREEN *sp) |
641 |
|
|
/* initialize the mouse */ |
642 |
|
|
{ |
643 |
|
|
bool result = FALSE; |
644 |
|
|
int i; |
645 |
|
|
|
646 |
|
|
if (sp != 0) { |
647 |
|
|
if (!sp->_mouse_initialized) { |
648 |
|
|
sp->_mouse_initialized = TRUE; |
649 |
|
|
|
650 |
|
|
TR(MY_TRACE, ("_nc_mouse_init() called")); |
651 |
|
|
|
652 |
|
|
sp->_mouse_eventp = FirstEV(sp); |
653 |
|
|
for (i = 0; i < EV_MAX; i++) |
654 |
|
|
sp->_mouse_events[i].id = INVALID_EVENT; |
655 |
|
|
|
656 |
|
|
initialize_mousetype(sp); |
657 |
|
|
|
658 |
|
|
T(("_nc_mouse_init() set mousetype to %d", sp->_mouse_type)); |
659 |
|
|
} |
660 |
|
|
result = sp->_mouse_initialized; |
661 |
|
|
} |
662 |
|
|
return result; |
663 |
|
|
} |
664 |
|
|
|
665 |
|
|
/* |
666 |
|
|
* Query to see if there is a pending mouse event. This is called from |
667 |
|
|
* fifo_push() in lib_getch.c |
668 |
|
|
*/ |
669 |
|
|
static bool |
670 |
|
|
_nc_mouse_event(SCREEN *sp GCC_UNUSED) |
671 |
|
|
{ |
672 |
|
|
MEVENT *eventp = sp->_mouse_eventp; |
673 |
|
|
bool result = FALSE; |
674 |
|
|
|
675 |
|
|
(void) eventp; |
676 |
|
|
|
677 |
|
|
switch (sp->_mouse_type) { |
678 |
|
|
case M_XTERM: |
679 |
|
|
/* xterm: never have to query, mouse events are in the keyboard stream */ |
680 |
|
|
#if USE_EMX_MOUSE |
681 |
|
|
{ |
682 |
|
|
char kbuf[3]; |
683 |
|
|
|
684 |
|
|
int i, res = read(M_FD(sp), &kbuf, 3); /* Eat the prefix */ |
685 |
|
|
if (res != 3) |
686 |
|
|
printf("Got %d chars instead of 3 for prefix.\n", res); |
687 |
|
|
for (i = 0; i < res; i++) { |
688 |
|
|
if (kbuf[i] != key_mouse[i]) |
689 |
|
|
printf("Got char %d instead of %d for prefix.\n", |
690 |
|
|
(int) kbuf[i], (int) key_mouse[i]); |
691 |
|
|
} |
692 |
|
|
result = TRUE; |
693 |
|
|
} |
694 |
|
|
#endif /* USE_EMX_MOUSE */ |
695 |
|
|
break; |
696 |
|
|
|
697 |
|
|
#if USE_GPM_SUPPORT |
698 |
|
|
case M_GPM: |
699 |
|
|
{ |
700 |
|
|
/* query server for event, return TRUE if we find one */ |
701 |
|
|
Gpm_Event ev; |
702 |
|
|
|
703 |
|
|
if (my_Gpm_GetEvent(&ev) == 1) { |
704 |
|
|
/* there's only one mouse... */ |
705 |
|
|
eventp->id = NORMAL_EVENT; |
706 |
|
|
|
707 |
|
|
eventp->bstate = 0; |
708 |
|
|
switch (ev.type & 0x0f) { |
709 |
|
|
case (GPM_DOWN): |
710 |
|
|
if (ev.buttons & GPM_B_LEFT) |
711 |
|
|
eventp->bstate |= BUTTON1_PRESSED; |
712 |
|
|
if (ev.buttons & GPM_B_MIDDLE) |
713 |
|
|
eventp->bstate |= BUTTON2_PRESSED; |
714 |
|
|
if (ev.buttons & GPM_B_RIGHT) |
715 |
|
|
eventp->bstate |= BUTTON3_PRESSED; |
716 |
|
|
break; |
717 |
|
|
case (GPM_UP): |
718 |
|
|
if (ev.buttons & GPM_B_LEFT) |
719 |
|
|
eventp->bstate |= BUTTON1_RELEASED; |
720 |
|
|
if (ev.buttons & GPM_B_MIDDLE) |
721 |
|
|
eventp->bstate |= BUTTON2_RELEASED; |
722 |
|
|
if (ev.buttons & GPM_B_RIGHT) |
723 |
|
|
eventp->bstate |= BUTTON3_RELEASED; |
724 |
|
|
break; |
725 |
|
|
default: |
726 |
|
|
break; |
727 |
|
|
} |
728 |
|
|
|
729 |
|
|
eventp->x = ev.x - 1; |
730 |
|
|
eventp->y = ev.y - 1; |
731 |
|
|
eventp->z = 0; |
732 |
|
|
|
733 |
|
|
/* bump the next-free pointer into the circular list */ |
734 |
|
|
sp->_mouse_eventp = eventp = NEXT(eventp); |
735 |
|
|
result = TRUE; |
736 |
|
|
} |
737 |
|
|
} |
738 |
|
|
break; |
739 |
|
|
#endif |
740 |
|
|
|
741 |
|
|
#if USE_SYSMOUSE |
742 |
|
|
case M_SYSMOUSE: |
743 |
|
|
if (sp->_sysmouse_head < sp->_sysmouse_tail) { |
744 |
|
|
*eventp = sp->_sysmouse_fifo[sp->_sysmouse_head]; |
745 |
|
|
|
746 |
|
|
/* |
747 |
|
|
* Point the fifo-head to the next possible location. If there |
748 |
|
|
* are none, reset the indices. This may be interrupted by the |
749 |
|
|
* signal handler, doing essentially the same reset. |
750 |
|
|
*/ |
751 |
|
|
sp->_sysmouse_head += 1; |
752 |
|
|
if (sp->_sysmouse_head == sp->_sysmouse_tail) { |
753 |
|
|
sp->_sysmouse_tail = 0; |
754 |
|
|
sp->_sysmouse_head = 0; |
755 |
|
|
} |
756 |
|
|
|
757 |
|
|
/* bump the next-free pointer into the circular list */ |
758 |
|
|
sp->_mouse_eventp = eventp = NEXT(eventp); |
759 |
|
|
result = TRUE; |
760 |
|
|
} |
761 |
|
|
break; |
762 |
|
|
#endif /* USE_SYSMOUSE */ |
763 |
|
|
|
764 |
|
|
case M_NONE: |
765 |
|
|
break; |
766 |
|
|
} |
767 |
|
|
|
768 |
|
|
return result; /* true if we found an event */ |
769 |
|
|
} |
770 |
|
|
|
771 |
|
|
static bool |
772 |
|
|
_nc_mouse_inline(SCREEN *sp) |
773 |
|
|
/* mouse report received in the keyboard stream -- parse its info */ |
774 |
|
|
{ |
775 |
|
|
int b; |
776 |
|
|
bool result = FALSE; |
777 |
|
|
MEVENT *eventp = sp->_mouse_eventp; |
778 |
|
|
|
779 |
|
|
TR(MY_TRACE, ("_nc_mouse_inline() called")); |
780 |
|
|
|
781 |
|
|
if (sp->_mouse_type == M_XTERM) { |
782 |
|
|
unsigned char kbuf[4]; |
783 |
|
|
mmask_t prev; |
784 |
|
|
size_t grabbed; |
785 |
|
|
int res; |
786 |
|
|
|
787 |
|
|
/* This code requires that your xterm entry contain the kmous |
788 |
|
|
* capability and that it be set to the \E[M documented in the |
789 |
|
|
* Xterm Control Sequences reference. This is how we |
790 |
|
|
* arrange for mouse events to be reported via a KEY_MOUSE |
791 |
|
|
* return value from wgetch(). After this value is received, |
792 |
|
|
* _nc_mouse_inline() gets called and is immediately |
793 |
|
|
* responsible for parsing the mouse status information |
794 |
|
|
* following the prefix. |
795 |
|
|
* |
796 |
|
|
* The following quotes from the ctrlseqs.ms document in the |
797 |
|
|
* X distribution, describing the X mouse tracking feature: |
798 |
|
|
* |
799 |
|
|
* Parameters for all mouse tracking escape sequences |
800 |
|
|
* generated by xterm encode numeric parameters in a single |
801 |
|
|
* character as value+040. For example, ! is 1. |
802 |
|
|
* |
803 |
|
|
* On button press or release, xterm sends ESC [ M CbCxCy. |
804 |
|
|
* The low two bits of Cb encode button information: 0=MB1 |
805 |
|
|
* pressed, 1=MB2 pressed, 2=MB3 pressed, 3=release. The |
806 |
|
|
* upper bits encode what modifiers were down when the |
807 |
|
|
* button was pressed and are added together. 4=Shift, |
808 |
|
|
* 8=Meta, 16=Control. Cx and Cy are the x and y coordinates |
809 |
|
|
* of the mouse event. The upper left corner is (1,1). |
810 |
|
|
* |
811 |
|
|
* (End quote) By the time we get here, we've eaten the |
812 |
|
|
* key prefix. FYI, the loop below is necessary because |
813 |
|
|
* mouse click info isn't guaranteed to present as a |
814 |
|
|
* single clist item. |
815 |
|
|
* |
816 |
|
|
* Wheel mice may return buttons 4 and 5 when the wheel is turned. |
817 |
|
|
* We encode those as button presses. |
818 |
|
|
*/ |
819 |
|
|
for (grabbed = 0; grabbed < 3; grabbed += (size_t) res) { |
820 |
|
|
|
821 |
|
|
/* For VIO mouse we add extra bit 64 to disambiguate button-up. */ |
822 |
|
|
#if USE_EMX_MOUSE |
823 |
|
|
res = read(M_FD(sp) >= 0 ? M_FD(sp) : sp->_ifd, &kbuf, 3); |
824 |
|
|
#else |
825 |
|
|
res = read(sp->_ifd, kbuf + grabbed, 3 - grabbed); |
826 |
|
|
#endif |
827 |
|
|
if (res == -1) |
828 |
|
|
break; |
829 |
|
|
} |
830 |
|
|
kbuf[3] = '\0'; |
831 |
|
|
|
832 |
|
|
TR(TRACE_IEVENT, |
833 |
|
|
("_nc_mouse_inline sees the following xterm data: '%s'", kbuf)); |
834 |
|
|
|
835 |
|
|
/* there's only one mouse... */ |
836 |
|
|
eventp->id = NORMAL_EVENT; |
837 |
|
|
|
838 |
|
|
/* processing code goes here */ |
839 |
|
|
eventp->bstate = 0; |
840 |
|
|
prev = PREV(eventp)->bstate; |
841 |
|
|
|
842 |
|
|
#if USE_EMX_MOUSE |
843 |
|
|
#define PRESS_POSITION(n) \ |
844 |
|
|
eventp->bstate = MASK_PRESS(n); \ |
845 |
|
|
if (kbuf[0] & 0x40) \ |
846 |
|
|
eventp->bstate = MASK_RELEASE(n) |
847 |
|
|
#else |
848 |
|
|
#define PRESS_POSITION(n) \ |
849 |
|
|
eventp->bstate = (mmask_t) (prev & MASK_PRESS(n) \ |
850 |
|
|
? REPORT_MOUSE_POSITION \ |
851 |
|
|
: MASK_PRESS(n)) |
852 |
|
|
#endif |
853 |
|
|
|
854 |
|
|
switch (kbuf[0] & 0x3) { |
855 |
|
|
case 0x0: |
856 |
|
|
if (kbuf[0] & 64) |
857 |
|
|
eventp->bstate = MASK_PRESS(4); |
858 |
|
|
else |
859 |
|
|
PRESS_POSITION(1); |
860 |
|
|
break; |
861 |
|
|
|
862 |
|
|
case 0x1: |
863 |
|
|
#if NCURSES_MOUSE_VERSION == 2 |
864 |
|
|
if (kbuf[0] & 64) |
865 |
|
|
eventp->bstate = MASK_PRESS(5); |
866 |
|
|
else |
867 |
|
|
#endif |
868 |
|
|
PRESS_POSITION(2); |
869 |
|
|
break; |
870 |
|
|
|
871 |
|
|
case 0x2: |
872 |
|
|
PRESS_POSITION(3); |
873 |
|
|
break; |
874 |
|
|
|
875 |
|
|
case 0x3: |
876 |
|
|
/* |
877 |
|
|
* Release events aren't reported for individual buttons, just for |
878 |
|
|
* the button set as a whole. However, because there are normally |
879 |
|
|
* no mouse events under xterm that intervene between press and |
880 |
|
|
* release, we can infer the button actually released by looking at |
881 |
|
|
* the previous event. |
882 |
|
|
*/ |
883 |
|
|
if (prev & (BUTTON_PRESSED | BUTTON_RELEASED)) { |
884 |
|
|
eventp->bstate = BUTTON_RELEASED; |
885 |
|
|
for (b = 1; b <= MAX_BUTTONS; ++b) { |
886 |
|
|
if (!(prev & MASK_PRESS(b))) |
887 |
|
|
eventp->bstate &= ~MASK_RELEASE(b); |
888 |
|
|
} |
889 |
|
|
} else { |
890 |
|
|
/* |
891 |
|
|
* XFree86 xterm will return a stream of release-events to |
892 |
|
|
* let the application know where the mouse is going, if the |
893 |
|
|
* private mode 1002 or 1003 is enabled. |
894 |
|
|
*/ |
895 |
|
|
eventp->bstate = REPORT_MOUSE_POSITION; |
896 |
|
|
} |
897 |
|
|
break; |
898 |
|
|
} |
899 |
|
|
result = (eventp->bstate & REPORT_MOUSE_POSITION) ? TRUE : FALSE; |
900 |
|
|
|
901 |
|
|
if (kbuf[0] & 4) { |
902 |
|
|
eventp->bstate |= BUTTON_SHIFT; |
903 |
|
|
} |
904 |
|
|
if (kbuf[0] & 8) { |
905 |
|
|
eventp->bstate |= BUTTON_ALT; |
906 |
|
|
} |
907 |
|
|
if (kbuf[0] & 16) { |
908 |
|
|
eventp->bstate |= BUTTON_CTRL; |
909 |
|
|
} |
910 |
|
|
|
911 |
|
|
eventp->x = (kbuf[1] - ' ') - 1; |
912 |
|
|
eventp->y = (kbuf[2] - ' ') - 1; |
913 |
|
|
TR(MY_TRACE, |
914 |
|
|
("_nc_mouse_inline: primitive mouse-event %s has slot %ld", |
915 |
|
|
_nc_tracemouse(sp, eventp), |
916 |
|
|
(long) IndexEV(sp, eventp))); |
917 |
|
|
|
918 |
|
|
/* bump the next-free pointer into the circular list */ |
919 |
|
|
sp->_mouse_eventp = NEXT(eventp); |
920 |
|
|
#if 0 /* this return would be needed for QNX's mods to lib_getch.c */ |
921 |
|
|
return (TRUE); |
922 |
|
|
#endif |
923 |
|
|
} |
924 |
|
|
|
925 |
|
|
return (result); |
926 |
|
|
} |
927 |
|
|
|
928 |
|
|
static void |
929 |
|
|
mouse_activate(SCREEN *sp, bool on) |
930 |
|
|
{ |
931 |
|
|
if (!on && !sp->_mouse_initialized) |
932 |
|
|
return; |
933 |
|
|
|
934 |
|
|
if (!_nc_mouse_init(sp)) |
935 |
|
|
return; |
936 |
|
|
|
937 |
|
|
if (on) { |
938 |
|
|
|
939 |
|
|
switch (sp->_mouse_type) { |
940 |
|
|
case M_XTERM: |
941 |
|
|
#if NCURSES_EXT_FUNCS |
942 |
|
|
keyok(KEY_MOUSE, on); |
943 |
|
|
#endif |
944 |
|
|
TPUTS_TRACE("xterm mouse initialization"); |
945 |
|
|
enable_xterm_mouse(sp, 1); |
946 |
|
|
break; |
947 |
|
|
#if USE_GPM_SUPPORT |
948 |
|
|
case M_GPM: |
949 |
|
|
if (enable_gpm_mouse(sp, TRUE)) { |
950 |
|
|
sp->_mouse_fd = *(my_gpm_fd); |
951 |
|
|
T(("GPM mouse_fd %d", sp->_mouse_fd)); |
952 |
|
|
} |
953 |
|
|
break; |
954 |
|
|
#endif |
955 |
|
|
#if USE_SYSMOUSE |
956 |
|
|
case M_SYSMOUSE: |
957 |
|
|
signal(SIGUSR2, handle_sysmouse); |
958 |
|
|
sp->_mouse_active = TRUE; |
959 |
|
|
break; |
960 |
|
|
#endif |
961 |
|
|
case M_NONE: |
962 |
|
|
return; |
963 |
|
|
} |
964 |
|
|
/* Make runtime binding to cut down on object size of applications that |
965 |
|
|
* do not use the mouse (e.g., 'clear'). |
966 |
|
|
*/ |
967 |
|
|
sp->_mouse_event = _nc_mouse_event; |
968 |
|
|
sp->_mouse_inline = _nc_mouse_inline; |
969 |
|
|
sp->_mouse_parse = _nc_mouse_parse; |
970 |
|
|
sp->_mouse_resume = _nc_mouse_resume; |
971 |
|
|
sp->_mouse_wrap = _nc_mouse_wrap; |
972 |
|
|
} else { |
973 |
|
|
|
974 |
|
|
switch (sp->_mouse_type) { |
975 |
|
|
case M_XTERM: |
976 |
|
|
TPUTS_TRACE("xterm mouse deinitialization"); |
977 |
|
|
enable_xterm_mouse(sp, 0); |
978 |
|
|
break; |
979 |
|
|
#if USE_GPM_SUPPORT |
980 |
|
|
case M_GPM: |
981 |
|
|
enable_gpm_mouse(sp, FALSE); |
982 |
|
|
break; |
983 |
|
|
#endif |
984 |
|
|
#if USE_SYSMOUSE |
985 |
|
|
case M_SYSMOUSE: |
986 |
|
|
signal(SIGUSR2, SIG_IGN); |
987 |
|
|
sp->_mouse_active = FALSE; |
988 |
|
|
break; |
989 |
|
|
#endif |
990 |
|
|
case M_NONE: |
991 |
|
|
return; |
992 |
|
|
} |
993 |
|
|
} |
994 |
|
|
_nc_flush(); |
995 |
|
|
} |
996 |
|
|
|
997 |
|
|
/************************************************************************** |
998 |
|
|
* |
999 |
|
|
* Device-independent code |
1000 |
|
|
* |
1001 |
|
|
**************************************************************************/ |
1002 |
|
|
|
1003 |
|
|
static bool |
1004 |
|
|
_nc_mouse_parse(SCREEN *sp, int runcount) |
1005 |
|
|
/* parse a run of atomic mouse events into a gesture */ |
1006 |
|
|
{ |
1007 |
|
|
MEVENT *eventp = sp->_mouse_eventp; |
1008 |
|
|
MEVENT *ep, *runp, *next, *prev = PREV(eventp); |
1009 |
|
|
int n; |
1010 |
|
|
int b; |
1011 |
|
|
bool merge; |
1012 |
|
|
|
1013 |
|
|
TR(MY_TRACE, ("_nc_mouse_parse(%d) called", runcount)); |
1014 |
|
|
|
1015 |
|
|
/* |
1016 |
|
|
* When we enter this routine, the event list next-free pointer |
1017 |
|
|
* points just past a run of mouse events that we know were separated |
1018 |
|
|
* in time by less than the critical click interval. The job of this |
1019 |
|
|
* routine is to collapse this run into a single higher-level event |
1020 |
|
|
* or gesture. |
1021 |
|
|
* |
1022 |
|
|
* We accomplish this in two passes. The first pass merges press/release |
1023 |
|
|
* pairs into click events. The second merges runs of click events into |
1024 |
|
|
* double or triple-click events. |
1025 |
|
|
* |
1026 |
|
|
* It's possible that the run may not resolve to a single event (for |
1027 |
|
|
* example, if the user quadruple-clicks). If so, leading events |
1028 |
|
|
* in the run are ignored. |
1029 |
|
|
* |
1030 |
|
|
* Note that this routine is independent of the format of the specific |
1031 |
|
|
* format of the pointing-device's reports. We can use it to parse |
1032 |
|
|
* gestures on anything that reports press/release events on a per- |
1033 |
|
|
* button basis, as long as the device-dependent mouse code puts stuff |
1034 |
|
|
* on the queue in MEVENT format. |
1035 |
|
|
*/ |
1036 |
|
|
if (runcount == 1) { |
1037 |
|
|
TR(MY_TRACE, |
1038 |
|
|
("_nc_mouse_parse: returning simple mouse event %s at slot %ld", |
1039 |
|
|
_nc_tracemouse(sp, prev), |
1040 |
|
|
(long) IndexEV(sp, prev))); |
1041 |
|
|
return (prev->id >= NORMAL_EVENT) |
1042 |
|
|
? ((prev->bstate & sp->_mouse_mask) ? TRUE : FALSE) |
1043 |
|
|
: FALSE; |
1044 |
|
|
} |
1045 |
|
|
|
1046 |
|
|
/* find the start of the run */ |
1047 |
|
|
runp = eventp; |
1048 |
|
|
for (n = runcount; n > 0; n--) { |
1049 |
|
|
runp = PREV(runp); |
1050 |
|
|
} |
1051 |
|
|
|
1052 |
|
|
#ifdef TRACE |
1053 |
|
|
if (USE_TRACEF(TRACE_IEVENT)) { |
1054 |
|
|
_trace_slot(sp, "before mouse press/release merge:"); |
1055 |
|
|
_tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", |
1056 |
|
|
RunParams(sp, eventp, runp), |
1057 |
|
|
runcount); |
1058 |
|
|
_nc_unlock_global(tracef); |
1059 |
|
|
} |
1060 |
|
|
#endif /* TRACE */ |
1061 |
|
|
|
1062 |
|
|
/* first pass; merge press/release pairs */ |
1063 |
|
|
do { |
1064 |
|
|
merge = FALSE; |
1065 |
|
|
for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) { |
1066 |
|
|
|
1067 |
|
|
#define MASK_CHANGED(x) (!(ep->bstate & MASK_PRESS(x)) \ |
1068 |
|
|
== !(next->bstate & MASK_RELEASE(x))) |
1069 |
|
|
|
1070 |
|
|
if (ep->x == next->x && ep->y == next->y |
1071 |
|
|
&& (ep->bstate & BUTTON_PRESSED) |
1072 |
|
|
&& MASK_CHANGED(1) |
1073 |
|
|
&& MASK_CHANGED(2) |
1074 |
|
|
&& MASK_CHANGED(3) |
1075 |
|
|
&& MASK_CHANGED(4) |
1076 |
|
|
#if NCURSES_MOUSE_VERSION == 2 |
1077 |
|
|
&& MASK_CHANGED(5) |
1078 |
|
|
#endif |
1079 |
|
|
) { |
1080 |
|
|
for (b = 1; b <= MAX_BUTTONS; ++b) { |
1081 |
|
|
if ((sp->_mouse_mask & MASK_CLICK(b)) |
1082 |
|
|
&& (ep->bstate & MASK_PRESS(b))) { |
1083 |
|
|
ep->bstate &= ~MASK_PRESS(b); |
1084 |
|
|
ep->bstate |= MASK_CLICK(b); |
1085 |
|
|
merge = TRUE; |
1086 |
|
|
} |
1087 |
|
|
} |
1088 |
|
|
if (merge) |
1089 |
|
|
next->id = INVALID_EVENT; |
1090 |
|
|
} |
1091 |
|
|
} |
1092 |
|
|
} while |
1093 |
|
|
(merge); |
1094 |
|
|
|
1095 |
|
|
#ifdef TRACE |
1096 |
|
|
if (USE_TRACEF(TRACE_IEVENT)) { |
1097 |
|
|
_trace_slot(sp, "before mouse click merge:"); |
1098 |
|
|
_tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", |
1099 |
|
|
RunParams(sp, eventp, runp), |
1100 |
|
|
runcount); |
1101 |
|
|
_nc_unlock_global(tracef); |
1102 |
|
|
} |
1103 |
|
|
#endif /* TRACE */ |
1104 |
|
|
|
1105 |
|
|
/* |
1106 |
|
|
* Second pass; merge click runs. At this point, click events are |
1107 |
|
|
* each followed by one invalid event. We merge click events |
1108 |
|
|
* forward in the queue. |
1109 |
|
|
* |
1110 |
|
|
* NOTE: There is a problem with this design! If the application |
1111 |
|
|
* allows enough click events to pile up in the circular queue so |
1112 |
|
|
* they wrap around, it will cheerfully merge the newest forward |
1113 |
|
|
* into the oldest, creating a bogus doubleclick and confusing |
1114 |
|
|
* the queue-traversal logic rather badly. Generally this won't |
1115 |
|
|
* happen, because calling getmouse() marks old events invalid and |
1116 |
|
|
* ineligible for merges. The true solution to this problem would |
1117 |
|
|
* be to timestamp each MEVENT and perform the obvious sanity check, |
1118 |
|
|
* but the timer element would have to have sub-second resolution, |
1119 |
|
|
* which would get us into portability trouble. |
1120 |
|
|
*/ |
1121 |
|
|
do { |
1122 |
|
|
MEVENT *follower; |
1123 |
|
|
|
1124 |
|
|
merge = FALSE; |
1125 |
|
|
for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) |
1126 |
|
|
if (ep->id != INVALID_EVENT) { |
1127 |
|
|
if (next->id != INVALID_EVENT) |
1128 |
|
|
continue; |
1129 |
|
|
follower = NEXT(next); |
1130 |
|
|
if (follower->id == INVALID_EVENT) |
1131 |
|
|
continue; |
1132 |
|
|
|
1133 |
|
|
/* merge click events forward */ |
1134 |
|
|
if ((ep->bstate & BUTTON_CLICKED) |
1135 |
|
|
&& (follower->bstate & BUTTON_CLICKED)) { |
1136 |
|
|
for (b = 1; b <= MAX_BUTTONS; ++b) { |
1137 |
|
|
if ((sp->_mouse_mask & MASK_DOUBLE_CLICK(b)) |
1138 |
|
|
&& (follower->bstate & MASK_CLICK(b))) { |
1139 |
|
|
follower->bstate &= ~MASK_CLICK(b); |
1140 |
|
|
follower->bstate |= MASK_DOUBLE_CLICK(b); |
1141 |
|
|
merge = TRUE; |
1142 |
|
|
} |
1143 |
|
|
} |
1144 |
|
|
if (merge) |
1145 |
|
|
ep->id = INVALID_EVENT; |
1146 |
|
|
} |
1147 |
|
|
|
1148 |
|
|
/* merge double-click events forward */ |
1149 |
|
|
if ((ep->bstate & BUTTON_DOUBLE_CLICKED) |
1150 |
|
|
&& (follower->bstate & BUTTON_CLICKED)) { |
1151 |
|
|
for (b = 1; b <= MAX_BUTTONS; ++b) { |
1152 |
|
|
if ((sp->_mouse_mask & MASK_TRIPLE_CLICK(b)) |
1153 |
|
|
&& (follower->bstate & MASK_CLICK(b))) { |
1154 |
|
|
follower->bstate &= ~MASK_CLICK(b); |
1155 |
|
|
follower->bstate |= MASK_TRIPLE_CLICK(b); |
1156 |
|
|
merge = TRUE; |
1157 |
|
|
} |
1158 |
|
|
} |
1159 |
|
|
if (merge) |
1160 |
|
|
ep->id = INVALID_EVENT; |
1161 |
|
|
} |
1162 |
|
|
} |
1163 |
|
|
} while |
1164 |
|
|
(merge); |
1165 |
|
|
|
1166 |
|
|
#ifdef TRACE |
1167 |
|
|
if (USE_TRACEF(TRACE_IEVENT)) { |
1168 |
|
|
_trace_slot(sp, "before mouse event queue compaction:"); |
1169 |
|
|
_tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", |
1170 |
|
|
RunParams(sp, eventp, runp), |
1171 |
|
|
runcount); |
1172 |
|
|
_nc_unlock_global(tracef); |
1173 |
|
|
} |
1174 |
|
|
#endif /* TRACE */ |
1175 |
|
|
|
1176 |
|
|
/* |
1177 |
|
|
* Now try to throw away trailing events flagged invalid, or that |
1178 |
|
|
* don't match the current event mask. |
1179 |
|
|
*/ |
1180 |
|
|
for (; runcount; prev = PREV(eventp), runcount--) |
1181 |
|
|
if (prev->id == INVALID_EVENT || !(prev->bstate & sp->_mouse_mask)) { |
1182 |
|
|
sp->_mouse_eventp = eventp = prev; |
1183 |
|
|
} |
1184 |
|
|
#ifdef TRACE |
1185 |
|
|
if (USE_TRACEF(TRACE_IEVENT)) { |
1186 |
|
|
_trace_slot(sp, "after mouse event queue compaction:"); |
1187 |
|
|
_tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", |
1188 |
|
|
RunParams(sp, eventp, runp), |
1189 |
|
|
runcount); |
1190 |
|
|
_nc_unlock_global(tracef); |
1191 |
|
|
} |
1192 |
|
|
for (ep = runp; ep != eventp; ep = NEXT(ep)) |
1193 |
|
|
if (ep->id != INVALID_EVENT) |
1194 |
|
|
TR(MY_TRACE, |
1195 |
|
|
("_nc_mouse_parse: returning composite mouse event %s at slot %ld", |
1196 |
|
|
_nc_tracemouse(sp, ep), |
1197 |
|
|
(long) IndexEV(sp, ep))); |
1198 |
|
|
#endif /* TRACE */ |
1199 |
|
|
|
1200 |
|
|
/* after all this, do we have a valid event? */ |
1201 |
|
|
return (PREV(eventp)->id != INVALID_EVENT); |
1202 |
|
|
} |
1203 |
|
|
|
1204 |
|
|
static void |
1205 |
|
|
_nc_mouse_wrap(SCREEN *sp) |
1206 |
|
|
/* release mouse -- called by endwin() before shellout/exit */ |
1207 |
|
|
{ |
1208 |
|
|
TR(MY_TRACE, ("_nc_mouse_wrap() called")); |
1209 |
|
|
|
1210 |
|
|
switch (sp->_mouse_type) { |
1211 |
|
|
case M_XTERM: |
1212 |
|
|
if (sp->_mouse_mask) |
1213 |
|
|
mouse_activate(sp, FALSE); |
1214 |
|
|
break; |
1215 |
|
|
#if USE_GPM_SUPPORT |
1216 |
|
|
/* GPM: pass all mouse events to next client */ |
1217 |
|
|
case M_GPM: |
1218 |
|
|
if (sp->_mouse_mask) |
1219 |
|
|
mouse_activate(sp, FALSE); |
1220 |
|
|
break; |
1221 |
|
|
#endif |
1222 |
|
|
#if USE_SYSMOUSE |
1223 |
|
|
case M_SYSMOUSE: |
1224 |
|
|
mouse_activate(sp, FALSE); |
1225 |
|
|
break; |
1226 |
|
|
#endif |
1227 |
|
|
case M_NONE: |
1228 |
|
|
break; |
1229 |
|
|
} |
1230 |
|
|
} |
1231 |
|
|
|
1232 |
|
|
static void |
1233 |
|
|
_nc_mouse_resume(SCREEN *sp) |
1234 |
|
|
/* re-connect to mouse -- called by doupdate() after shellout */ |
1235 |
|
|
{ |
1236 |
|
|
TR(MY_TRACE, ("_nc_mouse_resume() called")); |
1237 |
|
|
|
1238 |
|
|
switch (sp->_mouse_type) { |
1239 |
|
|
case M_XTERM: |
1240 |
|
|
/* xterm: re-enable reporting */ |
1241 |
|
|
if (sp->_mouse_mask) |
1242 |
|
|
mouse_activate(sp, TRUE); |
1243 |
|
|
break; |
1244 |
|
|
|
1245 |
|
|
#if USE_GPM_SUPPORT |
1246 |
|
|
case M_GPM: |
1247 |
|
|
/* GPM: reclaim our event set */ |
1248 |
|
|
if (sp->_mouse_mask) |
1249 |
|
|
mouse_activate(sp, TRUE); |
1250 |
|
|
break; |
1251 |
|
|
#endif |
1252 |
|
|
|
1253 |
|
|
#if USE_SYSMOUSE |
1254 |
|
|
case M_SYSMOUSE: |
1255 |
|
|
mouse_activate(sp, TRUE); |
1256 |
|
|
break; |
1257 |
|
|
#endif |
1258 |
|
|
case M_NONE: |
1259 |
|
|
break; |
1260 |
|
|
} |
1261 |
|
|
} |
1262 |
|
|
|
1263 |
|
|
/************************************************************************** |
1264 |
|
|
* |
1265 |
|
|
* Mouse interface entry points for the API |
1266 |
|
|
* |
1267 |
|
|
**************************************************************************/ |
1268 |
|
|
|
1269 |
|
|
static int |
1270 |
|
|
_nc_getmouse(SCREEN *sp, MEVENT * aevent) |
1271 |
|
|
{ |
1272 |
|
|
T((T_CALLED("getmouse(%p)"), aevent)); |
1273 |
|
|
|
1274 |
|
|
if ((aevent != 0) && (sp != 0) && (sp->_mouse_type != M_NONE)) { |
1275 |
|
|
MEVENT *eventp = sp->_mouse_eventp; |
1276 |
|
|
/* compute the current-event pointer */ |
1277 |
|
|
MEVENT *prev = PREV(eventp); |
1278 |
|
|
|
1279 |
|
|
/* copy the event we find there */ |
1280 |
|
|
*aevent = *prev; |
1281 |
|
|
|
1282 |
|
|
TR(TRACE_IEVENT, ("getmouse: returning event %s from slot %ld", |
1283 |
|
|
_nc_tracemouse(sp, prev), |
1284 |
|
|
(long) IndexEV(sp, prev))); |
1285 |
|
|
|
1286 |
|
|
prev->id = INVALID_EVENT; /* so the queue slot becomes free */ |
1287 |
|
|
returnCode(OK); |
1288 |
|
|
} |
1289 |
|
|
returnCode(ERR); |
1290 |
|
|
} |
1291 |
|
|
|
1292 |
|
|
/* grab a copy of the current mouse event */ |
1293 |
|
|
NCURSES_EXPORT(int) |
1294 |
|
|
getmouse(MEVENT * aevent) |
1295 |
|
|
{ |
1296 |
|
|
return _nc_getmouse(SP, aevent); |
1297 |
|
|
} |
1298 |
|
|
|
1299 |
|
|
static int |
1300 |
|
|
_nc_ungetmouse(SCREEN *sp, MEVENT * aevent) |
1301 |
|
|
{ |
1302 |
|
|
int result = ERR; |
1303 |
|
|
|
1304 |
|
|
T((T_CALLED("ungetmouse(%p)"), aevent)); |
1305 |
|
|
|
1306 |
|
|
if (aevent != 0 && sp != 0) { |
1307 |
|
|
MEVENT *eventp = sp->_mouse_eventp; |
1308 |
|
|
|
1309 |
|
|
/* stick the given event in the next-free slot */ |
1310 |
|
|
*eventp = *aevent; |
1311 |
|
|
|
1312 |
|
|
/* bump the next-free pointer into the circular list */ |
1313 |
|
|
sp->_mouse_eventp = NEXT(eventp); |
1314 |
|
|
|
1315 |
|
|
/* push back the notification event on the keyboard queue */ |
1316 |
|
|
result = _nc_ungetch(sp, KEY_MOUSE); |
1317 |
|
|
} |
1318 |
|
|
returnCode(result); |
1319 |
|
|
} |
1320 |
|
|
|
1321 |
|
|
/* enqueue a synthesized mouse event to be seen by the next wgetch() */ |
1322 |
|
|
NCURSES_EXPORT(int) |
1323 |
|
|
ungetmouse(MEVENT * aevent) |
1324 |
|
|
{ |
1325 |
|
|
return _nc_ungetmouse(SP, aevent); |
1326 |
|
|
} |
1327 |
|
|
|
1328 |
|
|
NCURSES_EXPORT(mmask_t) |
1329 |
|
|
mousemask(mmask_t newmask, mmask_t * oldmask) |
1330 |
|
|
/* set the mouse event mask */ |
1331 |
|
|
{ |
1332 |
|
|
mmask_t result = 0; |
1333 |
|
|
|
1334 |
|
|
T((T_CALLED("mousemask(%#lx,%p)"), (unsigned long) newmask, oldmask)); |
1335 |
|
|
|
1336 |
|
|
if (SP != 0) { |
1337 |
|
|
if (oldmask) |
1338 |
|
|
*oldmask = SP->_mouse_mask; |
1339 |
|
|
|
1340 |
|
|
if (newmask || SP->_mouse_initialized) { |
1341 |
|
|
_nc_mouse_init(SP); |
1342 |
|
|
if (SP->_mouse_type != M_NONE) { |
1343 |
|
|
result = newmask & |
1344 |
|
|
(REPORT_MOUSE_POSITION |
1345 |
|
|
| BUTTON_ALT |
1346 |
|
|
| BUTTON_CTRL |
1347 |
|
|
| BUTTON_SHIFT |
1348 |
|
|
| BUTTON_PRESSED |
1349 |
|
|
| BUTTON_RELEASED |
1350 |
|
|
| BUTTON_CLICKED |
1351 |
|
|
| BUTTON_DOUBLE_CLICKED |
1352 |
|
|
| BUTTON_TRIPLE_CLICKED); |
1353 |
|
|
|
1354 |
|
|
mouse_activate(SP, (bool) (result != 0)); |
1355 |
|
|
|
1356 |
|
|
SP->_mouse_mask = result; |
1357 |
|
|
} |
1358 |
|
|
} |
1359 |
|
|
} |
1360 |
|
|
returnBits(result); |
1361 |
|
|
} |
1362 |
|
|
|
1363 |
|
|
NCURSES_EXPORT(bool) |
1364 |
|
|
wenclose(const WINDOW *win, int y, int x) |
1365 |
|
|
/* check to see if given window encloses given screen location */ |
1366 |
|
|
{ |
1367 |
|
|
bool result = FALSE; |
1368 |
|
|
|
1369 |
|
|
T((T_CALLED("wenclose(%p,%d,%d)"), win, y, x)); |
1370 |
|
|
|
1371 |
|
|
if (win != 0) { |
1372 |
|
|
y -= win->_yoffset; |
1373 |
|
|
result = ((win->_begy <= y && |
1374 |
|
|
win->_begx <= x && |
1375 |
|
|
(win->_begx + win->_maxx) >= x && |
1376 |
|
|
(win->_begy + win->_maxy) >= y) ? TRUE : FALSE); |
1377 |
|
|
} |
1378 |
|
|
returnBool(result); |
1379 |
|
|
} |
1380 |
|
|
|
1381 |
|
|
NCURSES_EXPORT(int) |
1382 |
|
|
mouseinterval(int maxclick) |
1383 |
|
|
/* set the maximum mouse interval within which to recognize a click */ |
1384 |
|
|
{ |
1385 |
|
|
int oldval; |
1386 |
|
|
|
1387 |
|
|
T((T_CALLED("mouseinterval(%d)"), maxclick)); |
1388 |
|
|
|
1389 |
|
|
if (SP != 0) { |
1390 |
|
|
oldval = SP->_maxclick; |
1391 |
|
|
if (maxclick >= 0) |
1392 |
|
|
SP->_maxclick = maxclick; |
1393 |
|
|
} else { |
1394 |
|
|
oldval = DEFAULT_MAXCLICK; |
1395 |
|
|
} |
1396 |
|
|
|
1397 |
|
|
returnCode(oldval); |
1398 |
|
|
} |
1399 |
|
|
|
1400 |
|
|
/* This may be used by other routines to ask for the existence of mouse |
1401 |
|
|
support */ |
1402 |
|
|
NCURSES_EXPORT(int) |
1403 |
|
|
_nc_has_mouse(void) |
1404 |
|
|
{ |
1405 |
|
|
return (SP->_mouse_type == M_NONE ? 0 : 1); |
1406 |
|
|
} |
1407 |
|
|
|
1408 |
|
|
NCURSES_EXPORT(bool) |
1409 |
|
|
wmouse_trafo(const WINDOW *win, int *pY, int *pX, bool to_screen) |
1410 |
|
|
{ |
1411 |
|
|
bool result = FALSE; |
1412 |
|
|
|
1413 |
|
|
T((T_CALLED("wmouse_trafo(%p,%p,%p,%d)"), win, pY, pX, to_screen)); |
1414 |
|
|
|
1415 |
|
|
if (win && pY && pX) { |
1416 |
|
|
int y = *pY; |
1417 |
|
|
int x = *pX; |
1418 |
|
|
|
1419 |
|
|
if (to_screen) { |
1420 |
|
|
y += win->_begy + win->_yoffset; |
1421 |
|
|
x += win->_begx; |
1422 |
|
|
if (wenclose(win, y, x)) |
1423 |
|
|
result = TRUE; |
1424 |
|
|
} else { |
1425 |
|
|
if (wenclose(win, y, x)) { |
1426 |
|
|
y -= (win->_begy + win->_yoffset); |
1427 |
|
|
x -= win->_begx; |
1428 |
|
|
result = TRUE; |
1429 |
|
|
} |
1430 |
|
|
} |
1431 |
|
|
if (result) { |
1432 |
|
|
*pX = x; |
1433 |
|
|
*pY = y; |
1434 |
|
|
} |
1435 |
|
|
} |
1436 |
|
|
returnBool(result); |
1437 |
|
|
} |