1 /****************************************************************************
2 * Copyright (c) 1998,1999,2000,2002 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
31 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
32 ****************************************************************************/
35 * This module is intended to encapsulate ncurses's interface to pointing
38 * The first method used is xterm's internal mouse-tracking facility.
39 * The second is Alessandro Rubini's GPM server.
41 * Notes for implementors of new mouse-interface methods:
43 * The code is logically split into a lower level that accepts event reports
44 * in a device-dependent format and an upper level that parses mouse gestures
45 * and filters events. The mediating data structure is a circular queue of
48 * Functionally, the lower level's job is to pick up primitive events and
49 * put them on the circular queue. This can happen in one of two ways:
50 * either (a) _nc_mouse_event() detects a series of incoming mouse reports
51 * and queues them, or (b) code in lib_getch.c detects the kmous prefix in
52 * the keyboard input stream and calls _nc_mouse_inline to queue up a series
53 * of adjacent mouse reports.
55 * In either case, _nc_mouse_parse() should be called after the series is
56 * accepted to parse the digested mouse reports (low-level MEVENTs) into
57 * a gesture (a high-level or composite MEVENT).
59 * Don't be too shy about adding new event types or modifiers, if you can find
60 * room for them in the 32-bit mask. The API is written so that users get
61 * feedback on which theoretical event types they won't see when they call
62 * mousemask. There's one bit per button (the RESERVED_EVENT bit) not being
63 * used yet, and a couple of bits open at the high end.
72 # define INCL_DOSPROCESS
73 # include <os2.h> /* Need to include before the others */
76 #include <curses.priv.h>
80 #ifndef LINT /* don't need this for llib-lncurses */
81 #undef buttons /* term.h defines this, and gpm uses it! */
83 #include <linux/keyboard.h> /* defines KG_* macros */
87 MODULE_ID("$Id: lib_mouse.c,v 1.58 2002/01/12 22:38:07 tom Exp $")
89 #define MY_TRACE TRACE_ICALLS|TRACE_IEVENT
91 #define INVALID_EVENT -1
94 #define M_XTERM -1 /* use xterm's mouse tracking? */
95 #define M_NONE 0 /* no mouse device */
96 #define M_GPM 1 /* use GPM */
97 #define M_QNX 2 /* QNX mouse on console */
98 #define M_QNX_TERM 3 /* QNX mouse on pterm/xterm (using qansi-m) */
102 static Gpm_Connect gpm_connect;
106 static mmask_t eventmask; /* current event mask */
108 static bool _nc_mouse_parse(int);
109 static void _nc_mouse_resume(SCREEN *);
110 static void _nc_mouse_wrap(SCREEN *);
112 /* maintain a circular list of mouse events */
114 /* The definition of the circular list size (EV_MAX), is in curses.priv.h, so
115 * wgetch() may refer to the size and call _nc_mouse_parse() before circular
118 static MEVENT events[EV_MAX]; /* hold the last mouse event seen */
119 static MEVENT *eventp = events; /* next free slot in event queue */
120 #define NEXT(ep) ((ep == events + EV_MAX - 1) ? events : ep + 1)
121 #define PREV(ep) ((ep == events) ? events + EV_MAX - 1 : ep - 1)
125 _trace_slot(const char *tag)
131 for (ep = events; ep < events + EV_MAX; ep++)
132 _tracef("mouse event queue slot %ld = %s",
133 (long) (ep - events),
143 static int mouse_wfd;
144 static int mouse_thread;
145 static int mouse_activated;
146 static char mouse_buttons[] =
149 # define M_FD(sp) sp->_mouse_fd
152 write_event(int down, int button, int x, int y)
155 unsigned long ignore;
157 strncpy(buf, key_mouse, 3); /* should be "\033[M" */
158 buf[3] = ' ' + (button - 1) + (down ? 0 : 0x40);
159 buf[4] = ' ' + x - LEFT_COL + 1;
160 buf[5] = ' ' + y - TOP_ROW + 1;
161 DosWrite(mouse_wfd, buf, 6, &ignore);
165 mouse_server(unsigned long ignored GCC_UNUSED)
167 unsigned short fWait = MOU_WAIT;
168 /* NOPTRRECT mourt = { 0,0,24,79 }; */
171 unsigned short mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN;
177 /* open the handle for the mouse */
178 if (MouOpen(NULL, &hmou) == 0) {
179 rc = MouSetEventMask(&mask, hmou);
180 if (rc) { /* retry with 2 buttons */
181 mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN;
182 rc = MouSetEventMask(&mask, hmou);
185 if (rc == 0 && MouDrawPtr(hmou) == 0) {
187 /* sit and wait on the event queue */
188 rc = MouReadEventQue(&mouev, &fWait, hmou);
190 sprintf(err, "Error reading mouse queue, rc=%lu.\r\n", rc);
193 if (!mouse_activated)
197 * OS/2 numbers a 3-button mouse inconsistently from other
203 if ((mouev.fs ^ oldstate) & MOUSE_BN1_DOWN)
204 write_event(mouev.fs & MOUSE_BN1_DOWN,
205 mouse_buttons[1], mouev.col, mouev.row);
206 if ((mouev.fs ^ oldstate) & MOUSE_BN2_DOWN)
207 write_event(mouev.fs & MOUSE_BN2_DOWN,
208 mouse_buttons[3], mouev.col, mouev.row);
209 if ((mouev.fs ^ oldstate) & MOUSE_BN3_DOWN)
210 write_event(mouev.fs & MOUSE_BN3_DOWN,
211 mouse_buttons[2], mouev.col, mouev.row);
217 sprintf(err, "Error setting event mask, buttons=%d, rc=%lu.\r\n",
220 DosWrite(2, err, strlen(err), &rc);
223 DosExit(EXIT_THREAD, 0L);
227 server_state(const int state)
228 { /* It would be nice to implement pointer-off and stop looping... */
229 mouse_activated = state;
234 static int initialized;
237 initialize_mousetype(void)
239 static const char *xterm_kmous = "\033[M";
241 /* Try gpm first, because gpm may be configured to run in xterm */
243 /* GPM: initialize connection to gpm server */
244 gpm_connect.eventMask = GPM_DOWN | GPM_UP;
245 gpm_connect.defaultMask = ~(gpm_connect.eventMask | GPM_HARD);
246 gpm_connect.minMod = 0;
247 gpm_connect.maxMod = ~((1 << KG_SHIFT) | (1 << KG_SHIFTL) | (1 << KG_SHIFTR));
248 if (Gpm_Open(&gpm_connect, 0) >= 0) { /* returns the file-descriptor */
250 SP->_mouse_fd = gpm_fd;
258 && strstr(cur_term->type.term_names, "xterm") == 0
262 if (pipe(handles) < 0) {
263 perror("mouse pipe error");
268 if (!mouse_buttons[0]) {
269 char *s = getenv("MOUSE_BUTTONS_123");
271 mouse_buttons[0] = 1;
272 if (s && strlen(s) >= 3) {
273 mouse_buttons[1] = s[0] - '0';
274 mouse_buttons[2] = s[1] - '0';
275 mouse_buttons[3] = s[2] - '0';
278 mouse_wfd = handles[1];
279 M_FD(SP) = handles[0];
281 setmode(handles[0], O_BINARY);
282 setmode(handles[1], O_BINARY);
283 /* Do not use CRT functions, we may single-threaded. */
284 rc = DosCreateThread((unsigned long *) &mouse_thread,
285 mouse_server, 0, 0, 8192);
287 printf("mouse thread error %d=%#x", rc, rc);
297 /* we know how to recognize mouse events under "xterm" */
298 if (key_mouse != 0) {
299 if (!strcmp(key_mouse, xterm_kmous)) {
303 } else if (strstr(cur_term->type.term_names, "xterm") != 0) {
304 (void) _nc_add_to_try(&(SP->_keytry), xterm_kmous, KEY_MOUSE);
312 /* initialize the mouse */
319 TR(MY_TRACE, ("_nc_mouse_init() called"));
321 for (i = 0; i < EV_MAX; i++)
322 events[i].id = INVALID_EVENT;
324 initialize_mousetype();
326 T(("_nc_mouse_init() set mousetype to %d", mousetype));
331 _nc_mouse_event(SCREEN * sp GCC_UNUSED)
332 /* query to see if there is a pending mouse event */
335 /* GPM: query server for event, return TRUE if we find one */
339 && (_nc_timed_wait(3, 0, (int *) 0) & 2) != 0
340 && Gpm_GetEvent(&ev) == 1) {
341 eventp->id = 0; /* there's only one mouse... */
344 switch (ev.type & 0x0f) {
346 if (ev.buttons & GPM_B_LEFT)
347 eventp->bstate |= BUTTON1_PRESSED;
348 if (ev.buttons & GPM_B_MIDDLE)
349 eventp->bstate |= BUTTON2_PRESSED;
350 if (ev.buttons & GPM_B_RIGHT)
351 eventp->bstate |= BUTTON3_PRESSED;
354 if (ev.buttons & GPM_B_LEFT)
355 eventp->bstate |= BUTTON1_RELEASED;
356 if (ev.buttons & GPM_B_MIDDLE)
357 eventp->bstate |= BUTTON2_RELEASED;
358 if (ev.buttons & GPM_B_RIGHT)
359 eventp->bstate |= BUTTON3_RELEASED;
365 eventp->x = ev.x - 1;
366 eventp->y = ev.y - 1;
369 /* bump the next-free pointer into the circular list */
370 eventp = NEXT(eventp);
376 if (SP->_mouse_fd >= 0
377 && (_nc_timed_wait(3, 0, (int *) 0) & 2) != 0) {
380 int i, res = read(M_FD(sp), &kbuf, 3); /* Eat the prefix */
382 printf("Got %d chars instead of 3 for prefix.\n", res);
383 for (i = 0; i < res; i++) {
384 if (kbuf[i] != key_mouse[i])
385 printf("Got char %d instead of %d for prefix.\n",
386 (int) kbuf[i], (int) key_mouse[i]);
390 #endif /* USE_EMX_MOUSE */
392 /* xterm: never have to query, mouse events are in the keyboard stream */
393 return (FALSE); /* no event waiting */
397 _nc_mouse_inline(SCREEN * sp)
398 /* mouse report received in the keyboard stream -- parse its info */
400 TR(MY_TRACE, ("_nc_mouse_inline() called"));
402 if (mousetype == M_XTERM) {
403 unsigned char kbuf[4];
408 /* This code requires that your xterm entry contain the kmous
409 * capability and that it be set to the \E[M documented in the
410 * Xterm Control Sequences reference. This is how we
411 * arrange for mouse events to be reported via a KEY_MOUSE
412 * return value from wgetch(). After this value is received,
413 * _nc_mouse_inline() gets called and is immediately
414 * responsible for parsing the mouse status information
415 * following the prefix.
417 * The following quotes from the ctrlseqs.ms document in the
418 * X distribution, describing the X mouse tracking feature:
420 * Parameters for all mouse tracking escape sequences
421 * generated by xterm encode numeric parameters in a single
422 * character as value+040. For example, ! is 1.
424 * On button press or release, xterm sends ESC [ M CbCxCy.
425 * The low two bits of Cb encode button information: 0=MB1
426 * pressed, 1=MB2 pressed, 2=MB3 pressed, 3=release. The
427 * upper bits encode what modifiers were down when the
428 * button was pressed and are added together. 4=Shift,
429 * 8=Meta, 16=Control. Cx and Cy are the x and y coordinates
430 * of the mouse event. The upper left corner is (1,1).
432 * (End quote) By the time we get here, we've eaten the
433 * key prefix. FYI, the loop below is necessary because
434 * mouse click info isn't guaranteed to present as a
435 * single clist item. It always does under Linux but often
436 * fails to under Solaris.
438 for (grabbed = 0; grabbed < 3; grabbed += res) {
440 /* For VIO mouse we add extra bit 64 to disambiguate button-up. */
442 res = read(M_FD(sp) >= 0 ? M_FD(sp) : sp->_ifd, &kbuf, 3);
444 res = read(sp->_ifd, kbuf + grabbed, 3 - grabbed);
452 ("_nc_mouse_inline sees the following xterm data: '%s'", kbuf));
454 eventp->id = 0; /* there's only one mouse... */
456 /* processing code goes here */
458 switch (kbuf[0] & 0x3) {
460 eventp->bstate = BUTTON1_PRESSED;
463 eventp->bstate = BUTTON1_RELEASED;
468 eventp->bstate = BUTTON2_PRESSED;
471 eventp->bstate = BUTTON2_RELEASED;
476 eventp->bstate = BUTTON3_PRESSED;
479 eventp->bstate = BUTTON3_RELEASED;
485 * Release events aren't reported for individual buttons,
486 * just for the button set as a whole...
493 * ...however, because there are no kinds of mouse events under
494 * xterm that can intervene between press and release, we can
495 * deduce which buttons were actually released by looking at the
499 if (!(prev->bstate & BUTTON1_PRESSED))
500 eventp->bstate &= ~BUTTON1_RELEASED;
501 if (!(prev->bstate & BUTTON2_PRESSED))
502 eventp->bstate &= ~BUTTON2_RELEASED;
503 if (!(prev->bstate & BUTTON3_PRESSED))
504 eventp->bstate &= ~BUTTON3_RELEASED;
509 eventp->bstate |= BUTTON_SHIFT;
512 eventp->bstate |= BUTTON_ALT;
515 eventp->bstate |= BUTTON_CTRL;
518 eventp->x = (kbuf[1] - ' ') - 1;
519 eventp->y = (kbuf[2] - ' ') - 1;
521 ("_nc_mouse_inline: primitive mouse-event %s has slot %ld",
523 (long) (eventp - events)));
525 /* bump the next-free pointer into the circular list */
526 eventp = NEXT(eventp);
527 #if 0 /* this return would be needed for QNX's mods to lib_getch.c */
536 mouse_activate(bool on)
538 if (!on && !initialized)
547 #if NCURSES_EXT_FUNCS
548 keyok(KEY_MOUSE, on);
550 TPUTS_TRACE("xterm mouse initialization");
559 SP->_mouse_fd = gpm_fd;
563 /* Make runtime binding to cut down on object size of applications that
564 * do not use the mouse (e.g., 'clear').
566 SP->_mouse_event = _nc_mouse_event;
567 SP->_mouse_inline = _nc_mouse_inline;
568 SP->_mouse_parse = _nc_mouse_parse;
569 SP->_mouse_resume = _nc_mouse_resume;
570 SP->_mouse_wrap = _nc_mouse_wrap;
576 TPUTS_TRACE("xterm mouse deinitialization");
592 /**************************************************************************
594 * Device-independent code
596 **************************************************************************/
599 _nc_mouse_parse(int runcount)
600 /* parse a run of atomic mouse events into a gesture */
602 MEVENT *ep, *runp, *next, *prev = PREV(eventp);
606 TR(MY_TRACE, ("_nc_mouse_parse(%d) called", runcount));
609 * When we enter this routine, the event list next-free pointer
610 * points just past a run of mouse events that we know were separated
611 * in time by less than the critical click interval. The job of this
612 * routine is to collaps this run into a single higher-level event
615 * We accomplish this in two passes. The first pass merges press/release
616 * pairs into click events. The second merges runs of click events into
617 * double or triple-click events.
619 * It's possible that the run may not resolve to a single event (for
620 * example, if the user quadruple-clicks). If so, leading events
621 * in the run are ignored.
623 * Note that this routine is independent of the format of the specific
624 * format of the pointing-device's reports. We can use it to parse
625 * gestures on anything that reports press/release events on a per-
626 * button basis, as long as the device-dependent mouse code puts stuff
627 * on the queue in MEVENT format.
631 ("_nc_mouse_parse: returning simple mouse event %s at slot %ld",
633 (long) (prev - events)));
634 return (prev->id >= 0)
635 ? ((prev->bstate & eventmask) ? TRUE : FALSE)
639 /* find the start of the run */
641 for (n = runcount; n > 0; n--) {
646 if (_nc_tracing & TRACE_IEVENT) {
647 _trace_slot("before mouse press/release merge:");
648 _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
649 (long) (runp - events),
650 (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX,
655 /* first pass; merge press/release pairs */
658 for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) {
659 if (ep->x == next->x && ep->y == next->y
660 && (ep->bstate & (BUTTON1_PRESSED | BUTTON2_PRESSED | BUTTON3_PRESSED))
661 && (!(ep->bstate & BUTTON1_PRESSED)
662 == !(next->bstate & BUTTON1_RELEASED))
663 && (!(ep->bstate & BUTTON2_PRESSED)
664 == !(next->bstate & BUTTON2_RELEASED))
665 && (!(ep->bstate & BUTTON3_PRESSED)
666 == !(next->bstate & BUTTON3_RELEASED))
668 if ((eventmask & BUTTON1_CLICKED)
669 && (ep->bstate & BUTTON1_PRESSED)) {
670 ep->bstate &= ~BUTTON1_PRESSED;
671 ep->bstate |= BUTTON1_CLICKED;
674 if ((eventmask & BUTTON2_CLICKED)
675 && (ep->bstate & BUTTON2_PRESSED)) {
676 ep->bstate &= ~BUTTON2_PRESSED;
677 ep->bstate |= BUTTON2_CLICKED;
680 if ((eventmask & BUTTON3_CLICKED)
681 && (ep->bstate & BUTTON3_PRESSED)) {
682 ep->bstate &= ~BUTTON3_PRESSED;
683 ep->bstate |= BUTTON3_CLICKED;
687 next->id = INVALID_EVENT;
694 if (_nc_tracing & TRACE_IEVENT) {
695 _trace_slot("before mouse click merge:");
696 _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
697 (long) (runp - events),
698 (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX,
704 * Second pass; merge click runs. At this point, click events are
705 * each followed by one invalid event. We merge click events
706 * forward in the queue.
708 * NOTE: There is a problem with this design! If the application
709 * allows enough click events to pile up in the circular queue so
710 * they wrap around, it will cheerfully merge the newest forward
711 * into the oldest, creating a bogus doubleclick and confusing
712 * the queue-traversal logic rather badly. Generally this won't
713 * happen, because calling getmouse() marks old events invalid and
714 * ineligible for merges. The true solution to this problem would
715 * be to timestamp each MEVENT and perform the obvious sanity check,
716 * but the timer element would have to have sub-second resolution,
717 * which would get us into portability trouble.
723 for (ep = runp; (next = NEXT(ep)) != eventp; ep = next)
724 if (ep->id != INVALID_EVENT) {
725 if (next->id != INVALID_EVENT)
727 follower = NEXT(next);
728 if (follower->id == INVALID_EVENT)
731 /* merge click events forward */
733 (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED))
734 && (follower->bstate &
735 (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED))) {
736 if ((eventmask & BUTTON1_DOUBLE_CLICKED)
737 && (follower->bstate & BUTTON1_CLICKED)) {
738 follower->bstate &= ~BUTTON1_CLICKED;
739 follower->bstate |= BUTTON1_DOUBLE_CLICKED;
742 if ((eventmask & BUTTON2_DOUBLE_CLICKED)
743 && (follower->bstate & BUTTON2_CLICKED)) {
744 follower->bstate &= ~BUTTON2_CLICKED;
745 follower->bstate |= BUTTON2_DOUBLE_CLICKED;
748 if ((eventmask & BUTTON3_DOUBLE_CLICKED)
749 && (follower->bstate & BUTTON3_CLICKED)) {
750 follower->bstate &= ~BUTTON3_CLICKED;
751 follower->bstate |= BUTTON3_DOUBLE_CLICKED;
755 ep->id = INVALID_EVENT;
758 /* merge double-click events forward */
760 (BUTTON1_DOUBLE_CLICKED
761 | BUTTON2_DOUBLE_CLICKED
762 | BUTTON3_DOUBLE_CLICKED))
763 && (follower->bstate &
764 (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED))) {
765 if ((eventmask & BUTTON1_TRIPLE_CLICKED)
766 && (follower->bstate & BUTTON1_CLICKED)) {
767 follower->bstate &= ~BUTTON1_CLICKED;
768 follower->bstate |= BUTTON1_TRIPLE_CLICKED;
771 if ((eventmask & BUTTON2_TRIPLE_CLICKED)
772 && (follower->bstate & BUTTON2_CLICKED)) {
773 follower->bstate &= ~BUTTON2_CLICKED;
774 follower->bstate |= BUTTON2_TRIPLE_CLICKED;
777 if ((eventmask & BUTTON3_TRIPLE_CLICKED)
778 && (follower->bstate & BUTTON3_CLICKED)) {
779 follower->bstate &= ~BUTTON3_CLICKED;
780 follower->bstate |= BUTTON3_TRIPLE_CLICKED;
784 ep->id = INVALID_EVENT;
791 if (_nc_tracing & TRACE_IEVENT) {
792 _trace_slot("before mouse event queue compaction:");
793 _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
794 (long) (runp - events),
795 (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX,
801 * Now try to throw away trailing events flagged invalid, or that
802 * don't match the current event mask.
804 for (; runcount; prev = PREV(eventp), runcount--)
805 if (prev->id == INVALID_EVENT || !(prev->bstate & eventmask)) {
809 if (_nc_tracing & TRACE_IEVENT) {
810 _trace_slot("after mouse event queue compaction:");
811 _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
812 (long) (runp - events),
813 (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX,
816 for (ep = runp; ep != eventp; ep = NEXT(ep))
817 if (ep->id != INVALID_EVENT)
819 ("_nc_mouse_parse: returning composite mouse event %s at slot %ld",
821 (long) (ep - events)));
824 /* after all this, do we have a valid event? */
825 return (PREV(eventp)->id != INVALID_EVENT);
829 _nc_mouse_wrap(SCREEN * sp GCC_UNUSED)
830 /* release mouse -- called by endwin() before shellout/exit */
832 TR(MY_TRACE, ("_nc_mouse_wrap() called"));
837 mouse_activate(FALSE);
840 /* GPM: pass all mouse events to next client */
848 _nc_mouse_resume(SCREEN * sp GCC_UNUSED)
849 /* re-connect to mouse -- called by doupdate() after shellout */
851 TR(MY_TRACE, ("_nc_mouse_resume() called"));
853 /* xterm: re-enable reporting */
854 if (mousetype == M_XTERM && eventmask)
855 mouse_activate(TRUE);
857 /* GPM: reclaim our event set */
860 /**************************************************************************
862 * Mouse interface entry points for the API
864 **************************************************************************/
867 getmouse(MEVENT * aevent)
868 /* grab a copy of the current mouse event */
870 T((T_CALLED("getmouse(%p)"), aevent));
872 if (aevent && (mousetype != M_NONE)) {
873 /* compute the current-event pointer */
874 MEVENT *prev = PREV(eventp);
876 /* copy the event we find there */
879 TR(TRACE_IEVENT, ("getmouse: returning event %s from slot %ld",
881 (long) (prev - events)));
883 prev->id = INVALID_EVENT; /* so the queue slot becomes free */
890 ungetmouse(MEVENT * aevent)
891 /* enqueue a synthesized mouse event to be seen by the next wgetch() */
893 /* stick the given event in the next-free slot */
896 /* bump the next-free pointer into the circular list */
897 eventp = NEXT(eventp);
899 /* push back the notification event on the keyboard queue */
900 return ungetch(KEY_MOUSE);
903 NCURSES_EXPORT(mmask_t)
904 mousemask(mmask_t newmask, mmask_t * oldmask)
905 /* set the mouse event mask */
909 T((T_CALLED("mousemask(%#lx,%p)"), newmask, oldmask));
912 *oldmask = eventmask;
914 if (!newmask && !initialized)
918 if (mousetype != M_NONE) {
919 eventmask = newmask &
920 (BUTTON_ALT | BUTTON_CTRL | BUTTON_SHIFT
921 | BUTTON1_PRESSED | BUTTON1_RELEASED | BUTTON1_CLICKED
922 | BUTTON1_DOUBLE_CLICKED | BUTTON1_TRIPLE_CLICKED
923 | BUTTON2_PRESSED | BUTTON2_RELEASED | BUTTON2_CLICKED
924 | BUTTON2_DOUBLE_CLICKED | BUTTON2_TRIPLE_CLICKED
925 | BUTTON3_PRESSED | BUTTON3_RELEASED | BUTTON3_CLICKED
926 | BUTTON3_DOUBLE_CLICKED | BUTTON3_TRIPLE_CLICKED);
928 mouse_activate(eventmask != 0);
937 wenclose(const WINDOW *win, int y, int x)
938 /* check to see if given window encloses given screen location */
942 return ((win->_begy <= y &&
944 (win->_begx + win->_maxx) >= x &&
945 (win->_begy + win->_maxy) >= y) ? TRUE : FALSE);
951 mouseinterval(int maxclick)
952 /* set the maximum mouse interval within which to recognize a click */
957 oldval = SP->_maxclick;
959 SP->_maxclick = maxclick;
961 oldval = DEFAULT_MAXCLICK;
967 /* This may be used by other routines to ask for the existence of mouse
972 return (mousetype == M_NONE ? 0 : 1);
977 (const WINDOW *win, int *pY, int *pX, bool to_screen)
981 if (win && pY && pX) {
986 y += win->_begy + win->_yoffset;
988 if (wenclose(win, y, x))
991 if (wenclose(win, y, x)) {
992 y -= (win->_begy + win->_yoffset);
1005 /* lib_mouse.c ends here */