1*c7ef0cfcSnicm /* $OpenBSD: lib_mouse.c,v 1.15 2023/10/17 09:52:08 nicm Exp $ */
292dd1ec0Smillert
392dd1ec0Smillert /****************************************************************************
4*c7ef0cfcSnicm * Copyright 2018-2022,2023 Thomas E. Dickey *
5*c7ef0cfcSnicm * Copyright 1998-2016,2017 Free Software Foundation, Inc. *
692dd1ec0Smillert * *
792dd1ec0Smillert * Permission is hereby granted, free of charge, to any person obtaining a *
892dd1ec0Smillert * copy of this software and associated documentation files (the *
992dd1ec0Smillert * "Software"), to deal in the Software without restriction, including *
1092dd1ec0Smillert * without limitation the rights to use, copy, modify, merge, publish, *
1192dd1ec0Smillert * distribute, distribute with modifications, sublicense, and/or sell *
1292dd1ec0Smillert * copies of the Software, and to permit persons to whom the Software is *
1392dd1ec0Smillert * furnished to do so, subject to the following conditions: *
1492dd1ec0Smillert * *
1592dd1ec0Smillert * The above copyright notice and this permission notice shall be included *
1692dd1ec0Smillert * in all copies or substantial portions of the Software. *
1792dd1ec0Smillert * *
1892dd1ec0Smillert * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
1992dd1ec0Smillert * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
2092dd1ec0Smillert * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
2192dd1ec0Smillert * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
2292dd1ec0Smillert * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
2392dd1ec0Smillert * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
2492dd1ec0Smillert * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
2592dd1ec0Smillert * *
2692dd1ec0Smillert * Except as contained in this notice, the name(s) of the above copyright *
2792dd1ec0Smillert * holders shall not be used in advertising or otherwise to promote the *
2892dd1ec0Smillert * sale, use or other dealings in this Software without prior written *
2992dd1ec0Smillert * authorization. *
3092dd1ec0Smillert ****************************************************************************/
3192dd1ec0Smillert
3292dd1ec0Smillert /****************************************************************************
3392dd1ec0Smillert * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
3492dd1ec0Smillert * and: Eric S. Raymond <esr@snark.thyrsus.com> *
3581d8c4e1Snicm * and: Thomas E. Dickey 1996-on *
36*c7ef0cfcSnicm * and: Juergen Pfeifer 2008 *
3792dd1ec0Smillert ****************************************************************************/
3892dd1ec0Smillert
3992dd1ec0Smillert /*
4092dd1ec0Smillert * This module is intended to encapsulate ncurses's interface to pointing
4192dd1ec0Smillert * devices.
4292dd1ec0Smillert *
4381d8c4e1Snicm * The primary method used is xterm's internal mouse-tracking facility.
4481d8c4e1Snicm * Additional methods depend on the platform:
4581d8c4e1Snicm * Alessandro Rubini's GPM server (Linux)
4681d8c4e1Snicm * sysmouse (FreeBSD)
4781d8c4e1Snicm * special-purpose mouse interface for OS/2 EMX.
4892dd1ec0Smillert *
4992dd1ec0Smillert * Notes for implementors of new mouse-interface methods:
5092dd1ec0Smillert *
5192dd1ec0Smillert * The code is logically split into a lower level that accepts event reports
5292dd1ec0Smillert * in a device-dependent format and an upper level that parses mouse gestures
5392dd1ec0Smillert * and filters events. The mediating data structure is a circular queue of
5492dd1ec0Smillert * MEVENT structures.
5592dd1ec0Smillert *
5692dd1ec0Smillert * Functionally, the lower level's job is to pick up primitive events and
5792dd1ec0Smillert * put them on the circular queue. This can happen in one of two ways:
5892dd1ec0Smillert * either (a) _nc_mouse_event() detects a series of incoming mouse reports
5992dd1ec0Smillert * and queues them, or (b) code in lib_getch.c detects the kmous prefix in
6092dd1ec0Smillert * the keyboard input stream and calls _nc_mouse_inline to queue up a series
6192dd1ec0Smillert * of adjacent mouse reports.
6292dd1ec0Smillert *
6392dd1ec0Smillert * In either case, _nc_mouse_parse() should be called after the series is
6492dd1ec0Smillert * accepted to parse the digested mouse reports (low-level MEVENTs) into
6592dd1ec0Smillert * a gesture (a high-level or composite MEVENT).
6692dd1ec0Smillert *
6792dd1ec0Smillert * Don't be too shy about adding new event types or modifiers, if you can find
6892dd1ec0Smillert * room for them in the 32-bit mask. The API is written so that users get
6992dd1ec0Smillert * feedback on which theoretical event types they won't see when they call
7092dd1ec0Smillert * mousemask. There's one bit per button (the RESERVED_EVENT bit) not being
7192dd1ec0Smillert * used yet, and a couple of bits open at the high end.
7292dd1ec0Smillert */
7392dd1ec0Smillert
7492dd1ec0Smillert #ifdef __EMX__
75b373e8e7Smillert # include <io.h>
7692dd1ec0Smillert # define INCL_DOS
7792dd1ec0Smillert # define INCL_VIO
7892dd1ec0Smillert # define INCL_KBD
7992dd1ec0Smillert # define INCL_MOU
8092dd1ec0Smillert # define INCL_DOSPROCESS
8192dd1ec0Smillert # include <os2.h> /* Need to include before the others */
8292dd1ec0Smillert #endif
8392dd1ec0Smillert
8492dd1ec0Smillert #include <curses.priv.h>
8581d8c4e1Snicm
86*c7ef0cfcSnicm #ifndef CUR
87*c7ef0cfcSnicm #define CUR SP_TERMTYPE
88*c7ef0cfcSnicm #endif
8981d8c4e1Snicm
90*c7ef0cfcSnicm MODULE_ID("$Id: lib_mouse.c,v 1.15 2023/10/17 09:52:08 nicm Exp $")
91*c7ef0cfcSnicm
9281d8c4e1Snicm #include <tic.h>
9392dd1ec0Smillert
9492dd1ec0Smillert #if USE_GPM_SUPPORT
95ed0e49f0Smillert #include <linux/keyboard.h> /* defines KG_* macros */
9692dd1ec0Smillert
9781d8c4e1Snicm #ifdef HAVE_LIBDL
9881d8c4e1Snicm /* use dynamic loader to avoid linkage dependency */
9981d8c4e1Snicm #include <dlfcn.h>
10081d8c4e1Snicm
10181d8c4e1Snicm #ifdef RTLD_NOW
10281d8c4e1Snicm #define my_RTLD RTLD_NOW
10381d8c4e1Snicm #else
10481d8c4e1Snicm #ifdef RTLD_LAZY
10581d8c4e1Snicm #define my_RTLD RTLD_LAZY
10681d8c4e1Snicm #else
10781d8c4e1Snicm make an error
10881d8c4e1Snicm #endif
10981d8c4e1Snicm #endif /* RTLD_NOW */
11081d8c4e1Snicm #endif /* HAVE_LIBDL */
11181d8c4e1Snicm
11281d8c4e1Snicm #endif /* USE_GPM_SUPPORT */
11381d8c4e1Snicm
11481d8c4e1Snicm #if USE_SYSMOUSE
11581d8c4e1Snicm #undef buttons /* symbol conflict in consio.h */
11681d8c4e1Snicm #undef mouse_info /* symbol conflict in consio.h */
11781d8c4e1Snicm #include <osreldate.h>
118*c7ef0cfcSnicm #if defined(__DragonFly_version) || (defined(__FreeBSD__) && (__FreeBSD_version >= 400017))
11981d8c4e1Snicm #include <sys/consio.h>
12081d8c4e1Snicm #include <sys/fbio.h>
12181d8c4e1Snicm #else
12281d8c4e1Snicm #include <machine/console.h>
12381d8c4e1Snicm #endif
12481d8c4e1Snicm #endif /* use_SYSMOUSE */
12592dd1ec0Smillert
126*c7ef0cfcSnicm #if USE_KLIBC_MOUSE
127*c7ef0cfcSnicm #include <sys/socket.h>
128*c7ef0cfcSnicm #define pipe(handles) socketpair(AF_LOCAL, SOCK_STREAM, 0, handles)
129*c7ef0cfcSnicm #define DosWrite(hfile, pbuffer, cbwrite, pcbactual) \
130*c7ef0cfcSnicm write(hfile, pbuffer, cbwrite)
131*c7ef0cfcSnicm #define DosExit(action, result ) /* do nothing */
132*c7ef0cfcSnicm #define DosCreateThread(ptid, pfn, param, flag, cbStack) \
133*c7ef0cfcSnicm (*(ptid) = _beginthread(pfn, NULL, cbStack, \
134*c7ef0cfcSnicm (void *)param), (*(ptid) == -1))
135*c7ef0cfcSnicm #endif
136*c7ef0cfcSnicm
13792dd1ec0Smillert #define MY_TRACE TRACE_ICALLS|TRACE_IEVENT
13892dd1ec0Smillert
139*c7ef0cfcSnicm #define MASK_RELEASE(x) (mmask_t) NCURSES_MOUSE_MASK(x, 001)
140*c7ef0cfcSnicm #define MASK_PRESS(x) (mmask_t) NCURSES_MOUSE_MASK(x, 002)
141*c7ef0cfcSnicm #define MASK_CLICK(x) (mmask_t) NCURSES_MOUSE_MASK(x, 004)
142*c7ef0cfcSnicm #define MASK_DOUBLE_CLICK(x) (mmask_t) NCURSES_MOUSE_MASK(x, 010)
143*c7ef0cfcSnicm #define MASK_TRIPLE_CLICK(x) (mmask_t) NCURSES_MOUSE_MASK(x, 020)
144*c7ef0cfcSnicm #define MASK_RESERVED_EVENT(x) (mmask_t) NCURSES_MOUSE_MASK(x, 040)
14592dd1ec0Smillert
14681d8c4e1Snicm #if NCURSES_MOUSE_VERSION == 1
147*c7ef0cfcSnicm
14881d8c4e1Snicm #define BUTTON_CLICKED (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED | BUTTON4_CLICKED)
14981d8c4e1Snicm #define BUTTON_PRESSED (BUTTON1_PRESSED | BUTTON2_PRESSED | BUTTON3_PRESSED | BUTTON4_PRESSED)
15081d8c4e1Snicm #define BUTTON_RELEASED (BUTTON1_RELEASED | BUTTON2_RELEASED | BUTTON3_RELEASED | BUTTON4_RELEASED)
15181d8c4e1Snicm #define BUTTON_DOUBLE_CLICKED (BUTTON1_DOUBLE_CLICKED | BUTTON2_DOUBLE_CLICKED | BUTTON3_DOUBLE_CLICKED | BUTTON4_DOUBLE_CLICKED)
15281d8c4e1Snicm #define BUTTON_TRIPLE_CLICKED (BUTTON1_TRIPLE_CLICKED | BUTTON2_TRIPLE_CLICKED | BUTTON3_TRIPLE_CLICKED | BUTTON4_TRIPLE_CLICKED)
153*c7ef0cfcSnicm
15481d8c4e1Snicm #define MAX_BUTTONS 4
155*c7ef0cfcSnicm
15681d8c4e1Snicm #else
157*c7ef0cfcSnicm
15881d8c4e1Snicm #define BUTTON_CLICKED (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED | BUTTON4_CLICKED | BUTTON5_CLICKED)
15981d8c4e1Snicm #define BUTTON_PRESSED (BUTTON1_PRESSED | BUTTON2_PRESSED | BUTTON3_PRESSED | BUTTON4_PRESSED | BUTTON5_PRESSED)
16081d8c4e1Snicm #define BUTTON_RELEASED (BUTTON1_RELEASED | BUTTON2_RELEASED | BUTTON3_RELEASED | BUTTON4_RELEASED | BUTTON5_RELEASED)
16181d8c4e1Snicm #define BUTTON_DOUBLE_CLICKED (BUTTON1_DOUBLE_CLICKED | BUTTON2_DOUBLE_CLICKED | BUTTON3_DOUBLE_CLICKED | BUTTON4_DOUBLE_CLICKED | BUTTON5_DOUBLE_CLICKED)
16281d8c4e1Snicm #define BUTTON_TRIPLE_CLICKED (BUTTON1_TRIPLE_CLICKED | BUTTON2_TRIPLE_CLICKED | BUTTON3_TRIPLE_CLICKED | BUTTON4_TRIPLE_CLICKED | BUTTON5_TRIPLE_CLICKED)
163*c7ef0cfcSnicm
164*c7ef0cfcSnicm #if NCURSES_MOUSE_VERSION == 2
16581d8c4e1Snicm #define MAX_BUTTONS 5
166*c7ef0cfcSnicm #else
167*c7ef0cfcSnicm #define MAX_BUTTONS 11
168*c7ef0cfcSnicm #endif
169*c7ef0cfcSnicm
17081d8c4e1Snicm #endif
17181d8c4e1Snicm
17281d8c4e1Snicm #define INVALID_EVENT -1
17381d8c4e1Snicm #define NORMAL_EVENT 0
17492dd1ec0Smillert
175*c7ef0cfcSnicm #define ValidEvent(ep) ((ep)->id != INVALID_EVENT)
176*c7ef0cfcSnicm #define Invalidate(ep) (ep)->id = INVALID_EVENT
177*c7ef0cfcSnicm
17892dd1ec0Smillert #if USE_GPM_SUPPORT
17981d8c4e1Snicm
18081d8c4e1Snicm #ifndef LIBGPM_SONAME
18181d8c4e1Snicm #define LIBGPM_SONAME "libgpm.so"
18292dd1ec0Smillert #endif
18392dd1ec0Smillert
184*c7ef0cfcSnicm #define GET_DLSYM(name) (my_##name = (TYPE_##name) dlsym(sp->_dlopen_gpm, #name))
18592dd1ec0Smillert
18681d8c4e1Snicm #endif /* USE_GPM_SUPPORT */
18781d8c4e1Snicm
18881d8c4e1Snicm static bool _nc_mouse_parse(SCREEN *, int);
18992dd1ec0Smillert static void _nc_mouse_resume(SCREEN *);
19092dd1ec0Smillert static void _nc_mouse_wrap(SCREEN *);
19192dd1ec0Smillert
19292dd1ec0Smillert /* maintain a circular list of mouse events */
19392dd1ec0Smillert
19481d8c4e1Snicm #define FirstEV(sp) ((sp)->_mouse_events)
19581d8c4e1Snicm #define LastEV(sp) ((sp)->_mouse_events + EV_MAX - 1)
19681d8c4e1Snicm
19781d8c4e1Snicm #undef NEXT
198*c7ef0cfcSnicm #define NEXT(ep) ((ep >= LastEV(SP_PARM)) \
199*c7ef0cfcSnicm ? FirstEV(SP_PARM) \
20081d8c4e1Snicm : ep + 1)
20181d8c4e1Snicm
20281d8c4e1Snicm #undef PREV
203*c7ef0cfcSnicm #define PREV(ep) ((ep <= FirstEV(SP_PARM)) \
204*c7ef0cfcSnicm ? LastEV(SP_PARM) \
20581d8c4e1Snicm : ep - 1)
20681d8c4e1Snicm
20781d8c4e1Snicm #define IndexEV(sp, ep) (ep - FirstEV(sp))
20881d8c4e1Snicm
20981d8c4e1Snicm #define RunParams(sp, eventp, runp) \
21081d8c4e1Snicm (long) IndexEV(sp, runp), \
21181d8c4e1Snicm (long) (IndexEV(sp, eventp) + (EV_MAX - 1)) % EV_MAX
21292dd1ec0Smillert
21392dd1ec0Smillert #ifdef TRACE
21423bb66c4Smillert static void
_trace_slot(SCREEN * sp,const char * tag)21581d8c4e1Snicm _trace_slot(SCREEN *sp, const char *tag)
21692dd1ec0Smillert {
21792dd1ec0Smillert MEVENT *ep;
21892dd1ec0Smillert
219*c7ef0cfcSnicm _tracef("%s", tag);
22092dd1ec0Smillert
22181d8c4e1Snicm for (ep = FirstEV(sp); ep <= LastEV(sp); ep++)
22292dd1ec0Smillert _tracef("mouse event queue slot %ld = %s",
22381d8c4e1Snicm (long) IndexEV(sp, ep),
22481d8c4e1Snicm _nc_tracemouse(sp, ep));
22592dd1ec0Smillert }
22692dd1ec0Smillert #endif
22792dd1ec0Smillert
22881d8c4e1Snicm #if USE_EMX_MOUSE
22992dd1ec0Smillert
23092dd1ec0Smillert # define TOP_ROW 0
23192dd1ec0Smillert # define LEFT_COL 0
23292dd1ec0Smillert
23392dd1ec0Smillert # define M_FD(sp) sp->_mouse_fd
23492dd1ec0Smillert
23592dd1ec0Smillert static void
write_event(SCREEN * sp,int down,int button,int x,int y)23681d8c4e1Snicm write_event(SCREEN *sp, int down, int button, int x, int y)
23792dd1ec0Smillert {
23892dd1ec0Smillert char buf[6];
23992dd1ec0Smillert unsigned long ignore;
24092dd1ec0Smillert
241*c7ef0cfcSnicm _nc_STRCPY(buf, "\033[M", sizeof(buf)); /* should be the same as key_mouse */
24292dd1ec0Smillert buf[3] = ' ' + (button - 1) + (down ? 0 : 0x40);
24392dd1ec0Smillert buf[4] = ' ' + x - LEFT_COL + 1;
24492dd1ec0Smillert buf[5] = ' ' + y - TOP_ROW + 1;
24581d8c4e1Snicm DosWrite(sp->_emxmouse_wfd, buf, 6, &ignore);
24692dd1ec0Smillert }
24792dd1ec0Smillert
24892dd1ec0Smillert static void
249*c7ef0cfcSnicm #if USE_KLIBC_MOUSE
mouse_server(void * param)250*c7ef0cfcSnicm mouse_server(void *param)
251*c7ef0cfcSnicm #else
25281d8c4e1Snicm mouse_server(unsigned long param)
253*c7ef0cfcSnicm #endif
25492dd1ec0Smillert {
25581d8c4e1Snicm SCREEN *sp = (SCREEN *) param;
25692dd1ec0Smillert unsigned short fWait = MOU_WAIT;
25792dd1ec0Smillert /* NOPTRRECT mourt = { 0,0,24,79 }; */
25892dd1ec0Smillert MOUEVENTINFO mouev;
25992dd1ec0Smillert HMOU hmou;
26092dd1ec0Smillert unsigned short mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN;
26177c4fa26Smillert int nbuttons = 3;
26292dd1ec0Smillert int oldstate = 0;
26377c4fa26Smillert char err[80];
26477c4fa26Smillert unsigned long rc;
26592dd1ec0Smillert
26692dd1ec0Smillert /* open the handle for the mouse */
26792dd1ec0Smillert if (MouOpen(NULL, &hmou) == 0) {
26877c4fa26Smillert rc = MouSetEventMask(&mask, hmou);
26977c4fa26Smillert if (rc) { /* retry with 2 buttons */
27077c4fa26Smillert mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN;
27177c4fa26Smillert rc = MouSetEventMask(&mask, hmou);
27277c4fa26Smillert nbuttons = 2;
27377c4fa26Smillert }
27477c4fa26Smillert if (rc == 0 && MouDrawPtr(hmou) == 0) {
27592dd1ec0Smillert for (;;) {
27692dd1ec0Smillert /* sit and wait on the event queue */
27777c4fa26Smillert rc = MouReadEventQue(&mouev, &fWait, hmou);
27877c4fa26Smillert if (rc) {
279*c7ef0cfcSnicm _nc_SPRINTF(err, _nc_SLIMIT(sizeof(err))
280*c7ef0cfcSnicm "Error reading mouse queue, rc=%lu.\r\n", rc);
28192dd1ec0Smillert break;
28277c4fa26Smillert }
28381d8c4e1Snicm if (!sp->_emxmouse_activated)
28492dd1ec0Smillert goto finish;
28592dd1ec0Smillert
28692dd1ec0Smillert /*
28792dd1ec0Smillert * OS/2 numbers a 3-button mouse inconsistently from other
28892dd1ec0Smillert * platforms:
28992dd1ec0Smillert * 1 = left
29092dd1ec0Smillert * 2 = right
29192dd1ec0Smillert * 3 = middle.
29292dd1ec0Smillert */
29392dd1ec0Smillert if ((mouev.fs ^ oldstate) & MOUSE_BN1_DOWN)
29481d8c4e1Snicm write_event(sp, mouev.fs & MOUSE_BN1_DOWN,
29581d8c4e1Snicm sp->_emxmouse_buttons[1], mouev.col, mouev.row);
29692dd1ec0Smillert if ((mouev.fs ^ oldstate) & MOUSE_BN2_DOWN)
29781d8c4e1Snicm write_event(sp, mouev.fs & MOUSE_BN2_DOWN,
29881d8c4e1Snicm sp->_emxmouse_buttons[3], mouev.col, mouev.row);
29992dd1ec0Smillert if ((mouev.fs ^ oldstate) & MOUSE_BN3_DOWN)
30081d8c4e1Snicm write_event(sp, mouev.fs & MOUSE_BN3_DOWN,
30181d8c4e1Snicm sp->_emxmouse_buttons[2], mouev.col, mouev.row);
30292dd1ec0Smillert
30392dd1ec0Smillert finish:
30492dd1ec0Smillert oldstate = mouev.fs;
30592dd1ec0Smillert }
306*c7ef0cfcSnicm } else {
307*c7ef0cfcSnicm _nc_SPRINTF(err, _nc_SLIMIT(sizeof(err))
308*c7ef0cfcSnicm "Error setting event mask, buttons=%d, rc=%lu.\r\n",
30977c4fa26Smillert nbuttons, rc);
310*c7ef0cfcSnicm }
31192dd1ec0Smillert
31277c4fa26Smillert DosWrite(2, err, strlen(err), &rc);
31392dd1ec0Smillert MouClose(hmou);
31492dd1ec0Smillert }
31592dd1ec0Smillert DosExit(EXIT_THREAD, 0L);
31692dd1ec0Smillert }
31777c4fa26Smillert
31881d8c4e1Snicm #endif /* USE_EMX_MOUSE */
31981d8c4e1Snicm
32081d8c4e1Snicm #if USE_SYSMOUSE
32192dd1ec0Smillert static void
sysmouse_server(SCREEN * sp)32281d8c4e1Snicm sysmouse_server(SCREEN *sp)
32381d8c4e1Snicm {
32481d8c4e1Snicm struct mouse_info the_mouse;
32581d8c4e1Snicm MEVENT *work;
32681d8c4e1Snicm
32781d8c4e1Snicm the_mouse.operation = MOUSE_GETINFO;
32881d8c4e1Snicm if (sp != 0
32981d8c4e1Snicm && sp->_mouse_fd >= 0
33081d8c4e1Snicm && sp->_sysmouse_tail < FIFO_SIZE
33181d8c4e1Snicm && ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) {
33281d8c4e1Snicm
33381d8c4e1Snicm if (sp->_sysmouse_head > sp->_sysmouse_tail) {
33481d8c4e1Snicm sp->_sysmouse_tail = 0;
33581d8c4e1Snicm sp->_sysmouse_head = 0;
33681d8c4e1Snicm }
33781d8c4e1Snicm work = &(sp->_sysmouse_fifo[sp->_sysmouse_tail]);
33881d8c4e1Snicm memset(work, 0, sizeof(*work));
33981d8c4e1Snicm work->id = NORMAL_EVENT; /* there's only one mouse... */
34081d8c4e1Snicm
34181d8c4e1Snicm sp->_sysmouse_old_buttons = sp->_sysmouse_new_buttons;
34281d8c4e1Snicm sp->_sysmouse_new_buttons = the_mouse.u.data.buttons & 0x7;
34381d8c4e1Snicm
34481d8c4e1Snicm if (sp->_sysmouse_new_buttons) {
34581d8c4e1Snicm if (sp->_sysmouse_new_buttons & 1)
34681d8c4e1Snicm work->bstate |= BUTTON1_PRESSED;
34781d8c4e1Snicm if (sp->_sysmouse_new_buttons & 2)
34881d8c4e1Snicm work->bstate |= BUTTON2_PRESSED;
34981d8c4e1Snicm if (sp->_sysmouse_new_buttons & 4)
35081d8c4e1Snicm work->bstate |= BUTTON3_PRESSED;
35181d8c4e1Snicm } else {
35281d8c4e1Snicm if (sp->_sysmouse_old_buttons & 1)
35381d8c4e1Snicm work->bstate |= BUTTON1_RELEASED;
35481d8c4e1Snicm if (sp->_sysmouse_old_buttons & 2)
35581d8c4e1Snicm work->bstate |= BUTTON2_RELEASED;
35681d8c4e1Snicm if (sp->_sysmouse_old_buttons & 4)
35781d8c4e1Snicm work->bstate |= BUTTON3_RELEASED;
35892dd1ec0Smillert }
35992dd1ec0Smillert
36081d8c4e1Snicm /* for cosmetic bug in syscons.c on FreeBSD 3.[34] */
36181d8c4e1Snicm the_mouse.operation = MOUSE_HIDE;
36281d8c4e1Snicm ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse);
36381d8c4e1Snicm the_mouse.operation = MOUSE_SHOW;
36481d8c4e1Snicm ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse);
36592dd1ec0Smillert
36681d8c4e1Snicm /*
36781d8c4e1Snicm * We're only interested if the button is pressed or released.
36881d8c4e1Snicm * FIXME: implement continuous event-tracking.
36981d8c4e1Snicm */
37081d8c4e1Snicm if (sp->_sysmouse_new_buttons != sp->_sysmouse_old_buttons) {
37181d8c4e1Snicm sp->_sysmouse_tail += 1;
37281d8c4e1Snicm }
37381d8c4e1Snicm work->x = the_mouse.u.data.x / sp->_sysmouse_char_width;
37481d8c4e1Snicm work->y = the_mouse.u.data.y / sp->_sysmouse_char_height;
37581d8c4e1Snicm }
37681d8c4e1Snicm }
37792dd1ec0Smillert
37823bb66c4Smillert static void
handle_sysmouse(int sig GCC_UNUSED)37981d8c4e1Snicm handle_sysmouse(int sig GCC_UNUSED)
38092dd1ec0Smillert {
381*c7ef0cfcSnicm sysmouse_server(CURRENT_SCREEN);
38281d8c4e1Snicm }
38381d8c4e1Snicm #endif /* USE_SYSMOUSE */
38481d8c4e1Snicm
385*c7ef0cfcSnicm #if !defined(USE_TERM_DRIVER) || defined(EXP_WIN32_DRIVER)
386*c7ef0cfcSnicm #define xterm_kmous "\033[M"
387*c7ef0cfcSnicm
38881d8c4e1Snicm static void
init_xterm_mouse(SCREEN * sp)38981d8c4e1Snicm init_xterm_mouse(SCREEN *sp)
39081d8c4e1Snicm {
39181d8c4e1Snicm sp->_mouse_type = M_XTERM;
392*c7ef0cfcSnicm sp->_mouse_format = MF_X10;
39381d8c4e1Snicm sp->_mouse_xtermcap = tigetstr("XM");
394*c7ef0cfcSnicm if (VALID_STRING(sp->_mouse_xtermcap)) {
395*c7ef0cfcSnicm char *code = strstr(sp->_mouse_xtermcap, "[?");
396*c7ef0cfcSnicm if (code != 0) {
397*c7ef0cfcSnicm code += 2;
398*c7ef0cfcSnicm while ((*code >= '0') && (*code <= '9')) {
399*c7ef0cfcSnicm char *next = code;
400*c7ef0cfcSnicm while ((*next >= '0') && (*next <= '9')) {
401*c7ef0cfcSnicm ++next;
40281d8c4e1Snicm }
403*c7ef0cfcSnicm if (!strncmp(code, "1006", (size_t) (next - code))) {
404*c7ef0cfcSnicm sp->_mouse_format = MF_SGR1006;
405*c7ef0cfcSnicm }
406*c7ef0cfcSnicm #ifdef EXP_XTERM_1005
407*c7ef0cfcSnicm if (!strncmp(code, "1005", (size_t) (next - code))) {
408*c7ef0cfcSnicm sp->_mouse_format = MF_XTERM_1005;
409*c7ef0cfcSnicm }
410*c7ef0cfcSnicm #endif
411*c7ef0cfcSnicm if (*next == ';') {
412*c7ef0cfcSnicm while (*next == ';') {
413*c7ef0cfcSnicm ++next;
414*c7ef0cfcSnicm }
415*c7ef0cfcSnicm code = next;
416*c7ef0cfcSnicm } else {
417*c7ef0cfcSnicm break;
418*c7ef0cfcSnicm }
419*c7ef0cfcSnicm }
420*c7ef0cfcSnicm }
421*c7ef0cfcSnicm } else {
422*c7ef0cfcSnicm int code = tigetnum("XM");
423*c7ef0cfcSnicm switch (code) {
424*c7ef0cfcSnicm #ifdef EXP_XTERM_1005
425*c7ef0cfcSnicm case 1005:
426*c7ef0cfcSnicm /* see "xterm+sm+1005" */
427*c7ef0cfcSnicm sp->_mouse_xtermcap = "\033[?1005;1000%?%p1%{1}%=%th%el%;";
428*c7ef0cfcSnicm sp->_mouse_format = MF_XTERM_1005;
429*c7ef0cfcSnicm break;
430*c7ef0cfcSnicm #endif
431*c7ef0cfcSnicm case 1006:
432*c7ef0cfcSnicm /* see "xterm+sm+1006" */
433*c7ef0cfcSnicm sp->_mouse_xtermcap = "\033[?1006;1000%?%p1%{1}%=%th%el%;";
434*c7ef0cfcSnicm sp->_mouse_format = MF_SGR1006;
435*c7ef0cfcSnicm break;
436*c7ef0cfcSnicm default:
437*c7ef0cfcSnicm sp->_mouse_xtermcap = "\033[?1000%?%p1%{1}%=%th%el%;";
438*c7ef0cfcSnicm break;
439*c7ef0cfcSnicm }
440*c7ef0cfcSnicm }
441*c7ef0cfcSnicm }
442*c7ef0cfcSnicm #endif
44381d8c4e1Snicm
44481d8c4e1Snicm static void
enable_xterm_mouse(SCREEN * sp,int enable)44581d8c4e1Snicm enable_xterm_mouse(SCREEN *sp, int enable)
44681d8c4e1Snicm {
447*c7ef0cfcSnicm TPUTS_TRACE(enable
448*c7ef0cfcSnicm ? "xterm mouse initialization"
449*c7ef0cfcSnicm : "xterm mouse deinitialization");
45081d8c4e1Snicm #if USE_EMX_MOUSE
45181d8c4e1Snicm sp->_emxmouse_activated = enable;
45281d8c4e1Snicm #else
453*c7ef0cfcSnicm NCURSES_PUTP2("xterm-mouse", TIPARM_1(sp->_mouse_xtermcap, enable));
45481d8c4e1Snicm #endif
45581d8c4e1Snicm sp->_mouse_active = enable;
45681d8c4e1Snicm }
45781d8c4e1Snicm
458*c7ef0cfcSnicm #if defined(USE_TERM_DRIVER)
459*c7ef0cfcSnicm static void
enable_win32_mouse(SCREEN * sp,int enable)460*c7ef0cfcSnicm enable_win32_mouse(SCREEN *sp, int enable)
461*c7ef0cfcSnicm {
462*c7ef0cfcSnicm #if defined(EXP_WIN32_DRIVER)
463*c7ef0cfcSnicm enable_xterm_mouse(sp, enable);
464*c7ef0cfcSnicm #else
465*c7ef0cfcSnicm sp->_mouse_active = enable;
466*c7ef0cfcSnicm #endif
467*c7ef0cfcSnicm }
468*c7ef0cfcSnicm #endif
469*c7ef0cfcSnicm
47081d8c4e1Snicm #if USE_GPM_SUPPORT
47181d8c4e1Snicm static bool
allow_gpm_mouse(SCREEN * sp GCC_UNUSED)472*c7ef0cfcSnicm allow_gpm_mouse(SCREEN *sp GCC_UNUSED)
47381d8c4e1Snicm {
47481d8c4e1Snicm bool result = FALSE;
47581d8c4e1Snicm
476*c7ef0cfcSnicm #if USE_WEAK_SYMBOLS
477*c7ef0cfcSnicm /* Danger Robinson: do not use dlopen for libgpm if already loaded */
478*c7ef0cfcSnicm if ((Gpm_Wgetch) != 0) {
479*c7ef0cfcSnicm if (!sp->_mouse_gpm_loaded) {
480*c7ef0cfcSnicm T(("GPM library was already dlopen'd, not by us"));
481*c7ef0cfcSnicm }
482*c7ef0cfcSnicm } else
483*c7ef0cfcSnicm #endif
48481d8c4e1Snicm /* GPM does printf's without checking if stdout is a terminal */
485*c7ef0cfcSnicm if (NC_ISATTY(fileno(stdout))) {
486*c7ef0cfcSnicm const char *list = getenv("NCURSES_GPM_TERMS");
487*c7ef0cfcSnicm const char *env = getenv("TERM");
48881d8c4e1Snicm if (list != 0) {
48981d8c4e1Snicm if (env != 0) {
49081d8c4e1Snicm result = _nc_name_match(list, env, "|:");
49181d8c4e1Snicm }
49281d8c4e1Snicm } else {
49381d8c4e1Snicm /* GPM checks the beginning of the $TERM variable to decide if it
49481d8c4e1Snicm * should pass xterm events through. There is no real advantage in
49581d8c4e1Snicm * allowing GPM to do this. Recent versions relax that check, and
49681d8c4e1Snicm * pretend that GPM can work with any terminal having the kmous
49781d8c4e1Snicm * capability. Perhaps that works for someone. If so, they can
49881d8c4e1Snicm * set the environment variable (above).
49981d8c4e1Snicm */
50081d8c4e1Snicm if (env != 0 && strstr(env, "linux") != 0) {
50181d8c4e1Snicm result = TRUE;
50281d8c4e1Snicm }
50381d8c4e1Snicm }
50481d8c4e1Snicm }
50581d8c4e1Snicm return result;
50681d8c4e1Snicm }
50781d8c4e1Snicm
50881d8c4e1Snicm #ifdef HAVE_LIBDL
50981d8c4e1Snicm static void
unload_gpm_library(SCREEN * sp)51081d8c4e1Snicm unload_gpm_library(SCREEN *sp)
51181d8c4e1Snicm {
512*c7ef0cfcSnicm if (sp->_dlopen_gpm != 0) {
51381d8c4e1Snicm T(("unload GPM library"));
51481d8c4e1Snicm sp->_mouse_gpm_loaded = FALSE;
51581d8c4e1Snicm sp->_mouse_fd = -1;
51681d8c4e1Snicm }
51781d8c4e1Snicm }
51881d8c4e1Snicm
51981d8c4e1Snicm static void
load_gpm_library(SCREEN * sp)52081d8c4e1Snicm load_gpm_library(SCREEN *sp)
52181d8c4e1Snicm {
52281d8c4e1Snicm sp->_mouse_gpm_found = FALSE;
523*c7ef0cfcSnicm
524*c7ef0cfcSnicm /*
525*c7ef0cfcSnicm * If we already had a successful dlopen, reuse it.
526*c7ef0cfcSnicm */
527*c7ef0cfcSnicm if (sp->_dlopen_gpm != 0) {
528*c7ef0cfcSnicm sp->_mouse_gpm_found = TRUE;
529*c7ef0cfcSnicm sp->_mouse_gpm_loaded = TRUE;
530*c7ef0cfcSnicm } else if ((sp->_dlopen_gpm = dlopen(LIBGPM_SONAME, my_RTLD)) != 0) {
531*c7ef0cfcSnicm #if (defined(__GNUC__) && (__GNUC__ >= 5)) || defined(__clang__)
532*c7ef0cfcSnicm #pragma GCC diagnostic push
533*c7ef0cfcSnicm #pragma GCC diagnostic ignored "-Wpedantic"
534*c7ef0cfcSnicm #endif
53581d8c4e1Snicm if (GET_DLSYM(gpm_fd) == 0 ||
53681d8c4e1Snicm GET_DLSYM(Gpm_Open) == 0 ||
53781d8c4e1Snicm GET_DLSYM(Gpm_Close) == 0 ||
53881d8c4e1Snicm GET_DLSYM(Gpm_GetEvent) == 0) {
539*c7ef0cfcSnicm #if (defined(__GNUC__) && (__GNUC__ >= 5)) || defined(__clang__)
540*c7ef0cfcSnicm #pragma GCC diagnostic pop
541*c7ef0cfcSnicm #endif
54281d8c4e1Snicm T(("GPM initialization failed: %s", dlerror()));
54381d8c4e1Snicm unload_gpm_library(sp);
544*c7ef0cfcSnicm dlclose(sp->_dlopen_gpm);
545*c7ef0cfcSnicm sp->_dlopen_gpm = 0;
54681d8c4e1Snicm } else {
54781d8c4e1Snicm sp->_mouse_gpm_found = TRUE;
54881d8c4e1Snicm sp->_mouse_gpm_loaded = TRUE;
54981d8c4e1Snicm }
55081d8c4e1Snicm }
55181d8c4e1Snicm }
552*c7ef0cfcSnicm #endif /* HAVE_LIBDL */
55381d8c4e1Snicm
55481d8c4e1Snicm static bool
enable_gpm_mouse(SCREEN * sp,bool enable)55581d8c4e1Snicm enable_gpm_mouse(SCREEN *sp, bool enable)
55681d8c4e1Snicm {
55781d8c4e1Snicm bool result;
55881d8c4e1Snicm
55981d8c4e1Snicm T((T_CALLED("enable_gpm_mouse(%d)"), enable));
56081d8c4e1Snicm
56181d8c4e1Snicm if (enable && !sp->_mouse_active) {
56281d8c4e1Snicm #ifdef HAVE_LIBDL
56381d8c4e1Snicm if (sp->_mouse_gpm_found && !sp->_mouse_gpm_loaded) {
56481d8c4e1Snicm load_gpm_library(sp);
56581d8c4e1Snicm }
56681d8c4e1Snicm #endif
56781d8c4e1Snicm if (sp->_mouse_gpm_loaded) {
568*c7ef0cfcSnicm int code;
569*c7ef0cfcSnicm
57081d8c4e1Snicm /* GPM: initialize connection to gpm server */
57181d8c4e1Snicm sp->_mouse_gpm_connect.eventMask = GPM_DOWN | GPM_UP;
57281d8c4e1Snicm sp->_mouse_gpm_connect.defaultMask =
57381d8c4e1Snicm (unsigned short) (~(sp->_mouse_gpm_connect.eventMask | GPM_HARD));
57481d8c4e1Snicm sp->_mouse_gpm_connect.minMod = 0;
57581d8c4e1Snicm sp->_mouse_gpm_connect.maxMod =
57681d8c4e1Snicm (unsigned short) (~((1 << KG_SHIFT) |
57781d8c4e1Snicm (1 << KG_SHIFTL) |
57881d8c4e1Snicm (1 << KG_SHIFTR)));
57981d8c4e1Snicm /*
58081d8c4e1Snicm * Note: GPM hardcodes \E[?1001s and \E[?1000h during its open.
58181d8c4e1Snicm * The former is recognized by wscons (SunOS), and the latter by
58281d8c4e1Snicm * xterm. Those will not show up in ncurses' traces.
58381d8c4e1Snicm */
584*c7ef0cfcSnicm code = my_Gpm_Open(&sp->_mouse_gpm_connect, 0);
585*c7ef0cfcSnicm result = (code >= 0);
586*c7ef0cfcSnicm
587*c7ef0cfcSnicm /*
588*c7ef0cfcSnicm * GPM can return a -2 if it is trying to do something with xterm.
589*c7ef0cfcSnicm * Ignore that, since it conflicts with our use of stdin.
590*c7ef0cfcSnicm */
591*c7ef0cfcSnicm if (code == -2) {
592*c7ef0cfcSnicm my_Gpm_Close();
593*c7ef0cfcSnicm }
59481d8c4e1Snicm } else {
59581d8c4e1Snicm result = FALSE;
59681d8c4e1Snicm }
59781d8c4e1Snicm sp->_mouse_active = result;
59881d8c4e1Snicm T(("GPM open %s", result ? "succeeded" : "failed"));
59981d8c4e1Snicm } else {
60081d8c4e1Snicm if (!enable && sp->_mouse_active) {
60181d8c4e1Snicm /* GPM: close connection to gpm server */
60281d8c4e1Snicm my_Gpm_Close();
60381d8c4e1Snicm sp->_mouse_active = FALSE;
60481d8c4e1Snicm T(("GPM closed"));
60581d8c4e1Snicm }
60681d8c4e1Snicm result = enable;
60781d8c4e1Snicm }
60881d8c4e1Snicm #ifdef HAVE_LIBDL
60981d8c4e1Snicm if (!result) {
61081d8c4e1Snicm unload_gpm_library(sp);
61181d8c4e1Snicm }
61281d8c4e1Snicm #endif
61381d8c4e1Snicm returnBool(result);
61481d8c4e1Snicm }
61581d8c4e1Snicm #endif /* USE_GPM_SUPPORT */
61681d8c4e1Snicm
61781d8c4e1Snicm static void
initialize_mousetype(SCREEN * sp)61881d8c4e1Snicm initialize_mousetype(SCREEN *sp)
61981d8c4e1Snicm {
62081d8c4e1Snicm T((T_CALLED("initialize_mousetype()")));
62192dd1ec0Smillert
62223bb66c4Smillert /* Try gpm first, because gpm may be configured to run in xterm */
62392dd1ec0Smillert #if USE_GPM_SUPPORT
624*c7ef0cfcSnicm if (allow_gpm_mouse(sp)) {
62581d8c4e1Snicm if (!sp->_mouse_gpm_loaded) {
62681d8c4e1Snicm #ifdef HAVE_LIBDL
62781d8c4e1Snicm load_gpm_library(sp);
62881d8c4e1Snicm #else /* !HAVE_LIBDL */
62981d8c4e1Snicm sp->_mouse_gpm_found = TRUE;
63081d8c4e1Snicm sp->_mouse_gpm_loaded = TRUE;
63192dd1ec0Smillert #endif
63281d8c4e1Snicm }
63381d8c4e1Snicm
63481d8c4e1Snicm /*
63581d8c4e1Snicm * The gpm_fd file-descriptor may be negative (xterm). So we have to
63681d8c4e1Snicm * maintain our notion of whether the mouse connection is active
63781d8c4e1Snicm * without testing the file-descriptor.
63881d8c4e1Snicm */
63981d8c4e1Snicm if (sp->_mouse_gpm_found && enable_gpm_mouse(sp, TRUE)) {
64081d8c4e1Snicm sp->_mouse_type = M_GPM;
64181d8c4e1Snicm sp->_mouse_fd = *(my_gpm_fd);
64281d8c4e1Snicm T(("GPM mouse_fd %d", sp->_mouse_fd));
64381d8c4e1Snicm returnVoid;
64481d8c4e1Snicm }
64581d8c4e1Snicm }
64681d8c4e1Snicm #endif /* USE_GPM_SUPPORT */
64792dd1ec0Smillert
64892dd1ec0Smillert /* OS/2 VIO */
64981d8c4e1Snicm #if USE_EMX_MOUSE
65081d8c4e1Snicm if (!sp->_emxmouse_thread
651*c7ef0cfcSnicm && strstr(SP_TERMTYPE term_names, "xterm") == 0
652*c7ef0cfcSnicm && NonEmpty(key_mouse)) {
65392dd1ec0Smillert int handles[2];
65477c4fa26Smillert
65592dd1ec0Smillert if (pipe(handles) < 0) {
65692dd1ec0Smillert perror("mouse pipe error");
65781d8c4e1Snicm returnVoid;
65892dd1ec0Smillert } else {
65992dd1ec0Smillert int rc;
66092dd1ec0Smillert
66181d8c4e1Snicm if (!sp->_emxmouse_buttons[0]) {
662*c7ef0cfcSnicm const char *s = getenv("MOUSE_BUTTONS_123");
66392dd1ec0Smillert
66481d8c4e1Snicm sp->_emxmouse_buttons[0] = 1;
66592dd1ec0Smillert if (s && strlen(s) >= 3) {
66681d8c4e1Snicm sp->_emxmouse_buttons[1] = s[0] - '0';
66781d8c4e1Snicm sp->_emxmouse_buttons[2] = s[1] - '0';
66881d8c4e1Snicm sp->_emxmouse_buttons[3] = s[2] - '0';
66981d8c4e1Snicm } else {
67081d8c4e1Snicm sp->_emxmouse_buttons[1] = 1;
67181d8c4e1Snicm sp->_emxmouse_buttons[2] = 3;
67281d8c4e1Snicm sp->_emxmouse_buttons[3] = 2;
67392dd1ec0Smillert }
67492dd1ec0Smillert }
67581d8c4e1Snicm sp->_emxmouse_wfd = handles[1];
67681d8c4e1Snicm M_FD(sp) = handles[0];
67792dd1ec0Smillert /* Needed? */
67892dd1ec0Smillert setmode(handles[0], O_BINARY);
67992dd1ec0Smillert setmode(handles[1], O_BINARY);
68092dd1ec0Smillert /* Do not use CRT functions, we may single-threaded. */
68181d8c4e1Snicm rc = DosCreateThread((unsigned long *) &sp->_emxmouse_thread,
68281d8c4e1Snicm mouse_server, (long) sp, 0, 8192);
68323bb66c4Smillert if (rc) {
68492dd1ec0Smillert printf("mouse thread error %d=%#x", rc, rc);
68523bb66c4Smillert } else {
68681d8c4e1Snicm sp->_mouse_type = M_XTERM;
68781d8c4e1Snicm }
68881d8c4e1Snicm returnVoid;
68981d8c4e1Snicm }
69081d8c4e1Snicm }
69181d8c4e1Snicm #endif /* USE_EMX_MOUSE */
69281d8c4e1Snicm
69381d8c4e1Snicm #if USE_SYSMOUSE
69481d8c4e1Snicm {
695*c7ef0cfcSnicm static char dev_tty[] = "/dev/tty";
69681d8c4e1Snicm struct mouse_info the_mouse;
69781d8c4e1Snicm char *the_device = 0;
69881d8c4e1Snicm
699*c7ef0cfcSnicm if (NC_ISATTY(sp->_ifd))
70081d8c4e1Snicm the_device = ttyname(sp->_ifd);
70181d8c4e1Snicm if (the_device == 0)
702*c7ef0cfcSnicm the_device = dev_tty;
70381d8c4e1Snicm
70481d8c4e1Snicm sp->_mouse_fd = open(the_device, O_RDWR);
70581d8c4e1Snicm
70681d8c4e1Snicm if (sp->_mouse_fd >= 0) {
70781d8c4e1Snicm /*
70881d8c4e1Snicm * sysmouse does not have a usable user interface for obtaining
70981d8c4e1Snicm * mouse events. The logical way to proceed (reading data on a
71081d8c4e1Snicm * stream) only works if one opens the device as root. Even in
71181d8c4e1Snicm * that mode, careful examination shows we lose events
71281d8c4e1Snicm * occasionally. The interface provided for user programs is to
71381d8c4e1Snicm * establish a signal handler. really.
71481d8c4e1Snicm *
71581d8c4e1Snicm * Take over SIGUSR2 for this purpose since SIGUSR1 is more
71681d8c4e1Snicm * likely to be used by an application. getch() will have to
71781d8c4e1Snicm * handle the misleading EINTR's.
71881d8c4e1Snicm */
71981d8c4e1Snicm signal(SIGUSR2, SIG_IGN);
72081d8c4e1Snicm the_mouse.operation = MOUSE_MODE;
72181d8c4e1Snicm the_mouse.u.mode.mode = 0;
72281d8c4e1Snicm the_mouse.u.mode.signal = SIGUSR2;
72381d8c4e1Snicm if (ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) {
72481d8c4e1Snicm signal(SIGUSR2, handle_sysmouse);
72581d8c4e1Snicm the_mouse.operation = MOUSE_SHOW;
72681d8c4e1Snicm ioctl(sp->_mouse_fd, CONS_MOUSECTL, &the_mouse);
72781d8c4e1Snicm
72881d8c4e1Snicm #if defined(FBIO_MODEINFO) || defined(CONS_MODEINFO) /* FreeBSD > 2.x */
72981d8c4e1Snicm {
73081d8c4e1Snicm #ifndef FBIO_GETMODE /* FreeBSD 3.x */
73181d8c4e1Snicm #define FBIO_GETMODE CONS_GET
73281d8c4e1Snicm #define FBIO_MODEINFO CONS_MODEINFO
73381d8c4e1Snicm #endif /* FBIO_GETMODE */
73481d8c4e1Snicm video_info_t the_video;
73581d8c4e1Snicm
73681d8c4e1Snicm if (ioctl(sp->_mouse_fd,
73781d8c4e1Snicm FBIO_GETMODE,
73881d8c4e1Snicm &the_video.vi_mode) != -1
73981d8c4e1Snicm && ioctl(sp->_mouse_fd,
74081d8c4e1Snicm FBIO_MODEINFO,
74181d8c4e1Snicm &the_video) != -1) {
74281d8c4e1Snicm sp->_sysmouse_char_width = the_video.vi_cwidth;
74381d8c4e1Snicm sp->_sysmouse_char_height = the_video.vi_cheight;
74481d8c4e1Snicm }
74581d8c4e1Snicm }
74681d8c4e1Snicm #endif /* defined(FBIO_MODEINFO) || defined(CONS_MODEINFO) */
74781d8c4e1Snicm
74881d8c4e1Snicm if (sp->_sysmouse_char_width <= 0)
74981d8c4e1Snicm sp->_sysmouse_char_width = 8;
75081d8c4e1Snicm if (sp->_sysmouse_char_height <= 0)
75181d8c4e1Snicm sp->_sysmouse_char_height = 16;
75281d8c4e1Snicm sp->_mouse_type = M_SYSMOUSE;
75381d8c4e1Snicm returnVoid;
75423bb66c4Smillert }
75592dd1ec0Smillert }
75692dd1ec0Smillert }
75781d8c4e1Snicm #endif /* USE_SYSMOUSE */
75892dd1ec0Smillert
759*c7ef0cfcSnicm #ifdef USE_TERM_DRIVER
760*c7ef0cfcSnicm CallDriver(sp, td_initmouse);
761*c7ef0cfcSnicm #endif
762*c7ef0cfcSnicm #if !defined(USE_TERM_DRIVER) || defined(EXP_WIN32_DRIVER)
76323bb66c4Smillert /* we know how to recognize mouse events under "xterm" */
764*c7ef0cfcSnicm if (NonEmpty(key_mouse)) {
76581d8c4e1Snicm init_xterm_mouse(sp);
766*c7ef0cfcSnicm } else if (strstr(SP_TERMTYPE term_names, "xterm") != 0) {
76781d8c4e1Snicm if (_nc_add_to_try(&(sp->_keytry), xterm_kmous, KEY_MOUSE) == OK)
76881d8c4e1Snicm init_xterm_mouse(sp);
76923bb66c4Smillert }
770*c7ef0cfcSnicm #endif
771*c7ef0cfcSnicm
77281d8c4e1Snicm returnVoid;
77323bb66c4Smillert }
77423bb66c4Smillert
77523bb66c4Smillert static bool
_nc_mouse_init(SCREEN * sp)77681d8c4e1Snicm _nc_mouse_init(SCREEN *sp)
77781d8c4e1Snicm /* initialize the mouse */
77892dd1ec0Smillert {
77981d8c4e1Snicm bool result = FALSE;
780*c7ef0cfcSnicm
781*c7ef0cfcSnicm T((T_CALLED("_nc_mouse_init(%p)"), (void *)sp));
78281d8c4e1Snicm
78381d8c4e1Snicm if (sp != 0) {
78481d8c4e1Snicm if (!sp->_mouse_initialized) {
785*c7ef0cfcSnicm int i;
786*c7ef0cfcSnicm
78781d8c4e1Snicm sp->_mouse_initialized = TRUE;
78881d8c4e1Snicm
789*c7ef0cfcSnicm TR(MY_TRACE, ("set _mouse_initialized"));
79081d8c4e1Snicm
79181d8c4e1Snicm sp->_mouse_eventp = FirstEV(sp);
79281d8c4e1Snicm for (i = 0; i < EV_MAX; i++)
793*c7ef0cfcSnicm Invalidate(sp->_mouse_events + i);
79481d8c4e1Snicm
79581d8c4e1Snicm initialize_mousetype(sp);
79681d8c4e1Snicm
797*c7ef0cfcSnicm T(("set _mouse_type to %d", sp->_mouse_type));
79881d8c4e1Snicm }
79981d8c4e1Snicm result = sp->_mouse_initialized;
80081d8c4e1Snicm }
801*c7ef0cfcSnicm returnCode(result);
80281d8c4e1Snicm }
80381d8c4e1Snicm
80481d8c4e1Snicm /*
80581d8c4e1Snicm * Query to see if there is a pending mouse event. This is called from
80681d8c4e1Snicm * fifo_push() in lib_getch.c
80781d8c4e1Snicm */
80881d8c4e1Snicm static bool
_nc_mouse_event(SCREEN * sp)809*c7ef0cfcSnicm _nc_mouse_event(SCREEN *sp)
81081d8c4e1Snicm {
81181d8c4e1Snicm MEVENT *eventp = sp->_mouse_eventp;
81281d8c4e1Snicm bool result = FALSE;
81381d8c4e1Snicm
81481d8c4e1Snicm (void) eventp;
81581d8c4e1Snicm
81681d8c4e1Snicm switch (sp->_mouse_type) {
81781d8c4e1Snicm case M_XTERM:
81881d8c4e1Snicm /* xterm: never have to query, mouse events are in the keyboard stream */
81981d8c4e1Snicm #if USE_EMX_MOUSE
82081d8c4e1Snicm {
82181d8c4e1Snicm char kbuf[3];
82281d8c4e1Snicm
82381d8c4e1Snicm int i, res = read(M_FD(sp), &kbuf, 3); /* Eat the prefix */
82481d8c4e1Snicm if (res != 3)
82581d8c4e1Snicm printf("Got %d chars instead of 3 for prefix.\n", res);
82681d8c4e1Snicm for (i = 0; i < res; i++) {
82781d8c4e1Snicm if (kbuf[i] != key_mouse[i])
82881d8c4e1Snicm printf("Got char %d instead of %d for prefix.\n",
82981d8c4e1Snicm (int) kbuf[i], (int) key_mouse[i]);
83081d8c4e1Snicm }
83181d8c4e1Snicm result = TRUE;
83281d8c4e1Snicm }
83381d8c4e1Snicm #endif /* USE_EMX_MOUSE */
83481d8c4e1Snicm break;
83581d8c4e1Snicm
83692dd1ec0Smillert #if USE_GPM_SUPPORT
83781d8c4e1Snicm case M_GPM:
838*c7ef0cfcSnicm if (sp->_mouse_fd >= 0) {
83981d8c4e1Snicm /* query server for event, return TRUE if we find one */
84092dd1ec0Smillert Gpm_Event ev;
84192dd1ec0Smillert
842*c7ef0cfcSnicm switch (my_Gpm_GetEvent(&ev)) {
843*c7ef0cfcSnicm case 0:
844*c7ef0cfcSnicm /* Connection closed, drop the mouse. */
845*c7ef0cfcSnicm sp->_mouse_fd = -1;
846*c7ef0cfcSnicm break;
847*c7ef0cfcSnicm case 1:
84881d8c4e1Snicm /* there's only one mouse... */
84981d8c4e1Snicm eventp->id = NORMAL_EVENT;
85092dd1ec0Smillert
85192dd1ec0Smillert eventp->bstate = 0;
85223bb66c4Smillert switch (ev.type & 0x0f) {
85392dd1ec0Smillert case (GPM_DOWN):
85423bb66c4Smillert if (ev.buttons & GPM_B_LEFT)
85523bb66c4Smillert eventp->bstate |= BUTTON1_PRESSED;
85623bb66c4Smillert if (ev.buttons & GPM_B_MIDDLE)
85723bb66c4Smillert eventp->bstate |= BUTTON2_PRESSED;
85823bb66c4Smillert if (ev.buttons & GPM_B_RIGHT)
85923bb66c4Smillert eventp->bstate |= BUTTON3_PRESSED;
86092dd1ec0Smillert break;
86192dd1ec0Smillert case (GPM_UP):
86223bb66c4Smillert if (ev.buttons & GPM_B_LEFT)
86323bb66c4Smillert eventp->bstate |= BUTTON1_RELEASED;
86423bb66c4Smillert if (ev.buttons & GPM_B_MIDDLE)
86523bb66c4Smillert eventp->bstate |= BUTTON2_RELEASED;
86623bb66c4Smillert if (ev.buttons & GPM_B_RIGHT)
86723bb66c4Smillert eventp->bstate |= BUTTON3_RELEASED;
86892dd1ec0Smillert break;
86992dd1ec0Smillert default:
870*c7ef0cfcSnicm eventp->bstate |= REPORT_MOUSE_POSITION;
87192dd1ec0Smillert break;
87292dd1ec0Smillert }
87392dd1ec0Smillert
87492dd1ec0Smillert eventp->x = ev.x - 1;
87592dd1ec0Smillert eventp->y = ev.y - 1;
87692dd1ec0Smillert eventp->z = 0;
87792dd1ec0Smillert
87892dd1ec0Smillert /* bump the next-free pointer into the circular list */
879*c7ef0cfcSnicm sp->_mouse_eventp = NEXT(eventp);
88081d8c4e1Snicm result = TRUE;
881*c7ef0cfcSnicm break;
88292dd1ec0Smillert }
88381d8c4e1Snicm }
88481d8c4e1Snicm break;
88592dd1ec0Smillert #endif
88692dd1ec0Smillert
88781d8c4e1Snicm #if USE_SYSMOUSE
88881d8c4e1Snicm case M_SYSMOUSE:
88981d8c4e1Snicm if (sp->_sysmouse_head < sp->_sysmouse_tail) {
89081d8c4e1Snicm *eventp = sp->_sysmouse_fifo[sp->_sysmouse_head];
89177c4fa26Smillert
89281d8c4e1Snicm /*
89381d8c4e1Snicm * Point the fifo-head to the next possible location. If there
89481d8c4e1Snicm * are none, reset the indices. This may be interrupted by the
89581d8c4e1Snicm * signal handler, doing essentially the same reset.
89681d8c4e1Snicm */
89781d8c4e1Snicm sp->_sysmouse_head += 1;
89881d8c4e1Snicm if (sp->_sysmouse_head == sp->_sysmouse_tail) {
89981d8c4e1Snicm sp->_sysmouse_tail = 0;
90081d8c4e1Snicm sp->_sysmouse_head = 0;
90177c4fa26Smillert }
90277c4fa26Smillert
90381d8c4e1Snicm /* bump the next-free pointer into the circular list */
90481d8c4e1Snicm sp->_mouse_eventp = eventp = NEXT(eventp);
90581d8c4e1Snicm result = TRUE;
90681d8c4e1Snicm }
90781d8c4e1Snicm break;
90881d8c4e1Snicm #endif /* USE_SYSMOUSE */
90981d8c4e1Snicm
910*c7ef0cfcSnicm #ifdef USE_TERM_DRIVER
911*c7ef0cfcSnicm case M_TERM_DRIVER:
912*c7ef0cfcSnicm while (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
913*c7ef0cfcSnicm *eventp = sp->_drv_mouse_fifo[sp->_drv_mouse_head];
914*c7ef0cfcSnicm
915*c7ef0cfcSnicm /*
916*c7ef0cfcSnicm * Point the fifo-head to the next possible location. If there
917*c7ef0cfcSnicm * are none, reset the indices.
918*c7ef0cfcSnicm */
919*c7ef0cfcSnicm sp->_drv_mouse_head += 1;
920*c7ef0cfcSnicm if (sp->_drv_mouse_head == sp->_drv_mouse_tail) {
921*c7ef0cfcSnicm sp->_drv_mouse_tail = 0;
922*c7ef0cfcSnicm sp->_drv_mouse_head = 0;
923*c7ef0cfcSnicm }
924*c7ef0cfcSnicm
925*c7ef0cfcSnicm /* bump the next-free pointer into the circular list */
926*c7ef0cfcSnicm sp->_mouse_eventp = eventp = NEXT(eventp);
927*c7ef0cfcSnicm result = TRUE;
928*c7ef0cfcSnicm }
929*c7ef0cfcSnicm break;
930*c7ef0cfcSnicm #endif
931*c7ef0cfcSnicm
93281d8c4e1Snicm case M_NONE:
93381d8c4e1Snicm break;
93481d8c4e1Snicm }
93581d8c4e1Snicm
93681d8c4e1Snicm return result; /* true if we found an event */
93792dd1ec0Smillert }
93892dd1ec0Smillert
93981d8c4e1Snicm #if USE_EMX_MOUSE
94081d8c4e1Snicm #define PRESS_POSITION(n) \
941*c7ef0cfcSnicm do { \
94281d8c4e1Snicm eventp->bstate = MASK_PRESS(n); \
943*c7ef0cfcSnicm sp->_mouse_bstate |= MASK_PRESS(n); \
944*c7ef0cfcSnicm if (button & 0x40) { \
945*c7ef0cfcSnicm eventp->bstate = MASK_RELEASE(n); \
946*c7ef0cfcSnicm sp->_mouse_bstate &= ~MASK_PRESS(n); \
947*c7ef0cfcSnicm } \
948*c7ef0cfcSnicm } while (0)
94981d8c4e1Snicm #else
95081d8c4e1Snicm #define PRESS_POSITION(n) \
951*c7ef0cfcSnicm do { \
952*c7ef0cfcSnicm eventp->bstate = (mmask_t) ((sp->_mouse_bstate & MASK_PRESS(n)) \
95381d8c4e1Snicm ? REPORT_MOUSE_POSITION \
954*c7ef0cfcSnicm : MASK_PRESS(n)); \
955*c7ef0cfcSnicm sp->_mouse_bstate |= MASK_PRESS(n); \
956*c7ef0cfcSnicm } while (0)
95781d8c4e1Snicm #endif
95881d8c4e1Snicm
959*c7ef0cfcSnicm static bool
handle_wheel(SCREEN * sp,MEVENT * eventp,int button,int wheel)960*c7ef0cfcSnicm handle_wheel(SCREEN *sp, MEVENT * eventp, int button, int wheel)
961*c7ef0cfcSnicm {
962*c7ef0cfcSnicm bool result = TRUE;
963*c7ef0cfcSnicm
964*c7ef0cfcSnicm switch (button & 3) {
965*c7ef0cfcSnicm case 0:
966*c7ef0cfcSnicm if (wheel) {
96781d8c4e1Snicm eventp->bstate = MASK_PRESS(4);
968*c7ef0cfcSnicm /* Do not record in sp->_mouse_bstate; there will be no
969*c7ef0cfcSnicm * corresponding release event.
970*c7ef0cfcSnicm */
971*c7ef0cfcSnicm } else {
97281d8c4e1Snicm PRESS_POSITION(1);
973*c7ef0cfcSnicm }
97492dd1ec0Smillert break;
975*c7ef0cfcSnicm case 1:
976*c7ef0cfcSnicm if (wheel) {
977*c7ef0cfcSnicm #if NCURSES_MOUSE_VERSION >= 2
97881d8c4e1Snicm eventp->bstate = MASK_PRESS(5);
979*c7ef0cfcSnicm /* See comment above for button 4 */
980*c7ef0cfcSnicm #else
981*c7ef0cfcSnicm /* Ignore this event as it is not a true press of the button */
982*c7ef0cfcSnicm eventp->bstate = REPORT_MOUSE_POSITION;
98392dd1ec0Smillert #endif
984*c7ef0cfcSnicm } else {
98581d8c4e1Snicm PRESS_POSITION(2);
986*c7ef0cfcSnicm }
98792dd1ec0Smillert break;
988*c7ef0cfcSnicm case 2:
98981d8c4e1Snicm PRESS_POSITION(3);
99092dd1ec0Smillert break;
991*c7ef0cfcSnicm default:
992*c7ef0cfcSnicm /*
993*c7ef0cfcSnicm * case 3 is sent when the mouse buttons are released.
994*c7ef0cfcSnicm *
995*c7ef0cfcSnicm * If the terminal uses xterm mode 1003, a continuous series of
996*c7ef0cfcSnicm * button-release events is sent as the mouse moves around the screen,
997*c7ef0cfcSnicm * or as the wheel mouse is rotated.
998*c7ef0cfcSnicm *
999*c7ef0cfcSnicm * Return false in this case, so that when running in X10 mode, we will
1000*c7ef0cfcSnicm * recalculate bstate.
1001*c7ef0cfcSnicm */
1002*c7ef0cfcSnicm eventp->bstate = REPORT_MOUSE_POSITION;
1003*c7ef0cfcSnicm result = FALSE;
1004*c7ef0cfcSnicm break;
1005*c7ef0cfcSnicm }
1006*c7ef0cfcSnicm return result;
1007*c7ef0cfcSnicm }
100892dd1ec0Smillert
1009*c7ef0cfcSnicm static bool
decode_X10_bstate(SCREEN * sp,MEVENT * eventp,unsigned intro)1010*c7ef0cfcSnicm decode_X10_bstate(SCREEN *sp, MEVENT * eventp, unsigned intro)
1011*c7ef0cfcSnicm {
1012*c7ef0cfcSnicm bool result;
1013*c7ef0cfcSnicm int button = 0;
1014*c7ef0cfcSnicm int wheel = (intro & 96) == 96;
1015*c7ef0cfcSnicm
1016*c7ef0cfcSnicm eventp->bstate = 0;
1017*c7ef0cfcSnicm
1018*c7ef0cfcSnicm if (intro >= 96) {
1019*c7ef0cfcSnicm if (intro >= 160) {
1020*c7ef0cfcSnicm button = (int) (intro - 152); /* buttons 8-11 */
1021*c7ef0cfcSnicm } else {
1022*c7ef0cfcSnicm button = (int) (intro - 92); /* buttons 4-7 */
1023*c7ef0cfcSnicm }
1024*c7ef0cfcSnicm } else {
1025*c7ef0cfcSnicm button = (intro & 3);
1026*c7ef0cfcSnicm }
1027*c7ef0cfcSnicm
1028*c7ef0cfcSnicm if (button > MAX_BUTTONS) {
1029*c7ef0cfcSnicm eventp->bstate = REPORT_MOUSE_POSITION;
1030*c7ef0cfcSnicm } else if (!handle_wheel(sp, eventp, (int) intro, wheel)) {
1031*c7ef0cfcSnicm
103292dd1ec0Smillert /*
103381d8c4e1Snicm * Release events aren't reported for individual buttons, just for
103481d8c4e1Snicm * the button set as a whole. However, because there are normally
103581d8c4e1Snicm * no mouse events under xterm that intervene between press and
103681d8c4e1Snicm * release, we can infer the button actually released by looking at
103781d8c4e1Snicm * the previous event.
103892dd1ec0Smillert */
1039*c7ef0cfcSnicm if (sp->_mouse_bstate & BUTTON_PRESSED) {
1040*c7ef0cfcSnicm int b;
1041*c7ef0cfcSnicm
104281d8c4e1Snicm eventp->bstate = BUTTON_RELEASED;
104381d8c4e1Snicm for (b = 1; b <= MAX_BUTTONS; ++b) {
1044*c7ef0cfcSnicm if (!(sp->_mouse_bstate & MASK_PRESS(b)))
104581d8c4e1Snicm eventp->bstate &= ~MASK_RELEASE(b);
104681d8c4e1Snicm }
1047*c7ef0cfcSnicm sp->_mouse_bstate = 0;
104881d8c4e1Snicm } else {
104992dd1ec0Smillert /*
1050*c7ef0cfcSnicm * xterm will return a stream of release-events to let the
1051*c7ef0cfcSnicm * application know where the mouse is going, if private mode
1052*c7ef0cfcSnicm * 1002 or 1003 is enabled.
105392dd1ec0Smillert */
105481d8c4e1Snicm eventp->bstate = REPORT_MOUSE_POSITION;
105581d8c4e1Snicm }
105692dd1ec0Smillert }
105792dd1ec0Smillert
1058*c7ef0cfcSnicm if (intro & 4) {
105992dd1ec0Smillert eventp->bstate |= BUTTON_SHIFT;
106092dd1ec0Smillert }
1061*c7ef0cfcSnicm if (intro & 8) {
106292dd1ec0Smillert eventp->bstate |= BUTTON_ALT;
106392dd1ec0Smillert }
1064*c7ef0cfcSnicm if (intro & 16) {
106592dd1ec0Smillert eventp->bstate |= BUTTON_CTRL;
106692dd1ec0Smillert }
1067*c7ef0cfcSnicm result = (eventp->bstate & REPORT_MOUSE_POSITION) ? TRUE : FALSE;
1068*c7ef0cfcSnicm return result;
1069*c7ef0cfcSnicm }
1070*c7ef0cfcSnicm
1071*c7ef0cfcSnicm /* This code requires that your xterm entry contain the kmous capability and
1072*c7ef0cfcSnicm * that it be set to the \E[M documented in the Xterm Control Sequences
1073*c7ef0cfcSnicm * reference. This is how we arrange for mouse events to be reported via a
1074*c7ef0cfcSnicm * KEY_MOUSE return value from wgetch(). After this value is received,
1075*c7ef0cfcSnicm * _nc_mouse_inline() gets called and is immediately responsible for parsing
1076*c7ef0cfcSnicm * the mouse status information following the prefix.
1077*c7ef0cfcSnicm *
1078*c7ef0cfcSnicm * The following quotes from the ctlseqs.ms document in the XTerm distribution,
1079*c7ef0cfcSnicm * describing the mouse tracking feature:
1080*c7ef0cfcSnicm *
1081*c7ef0cfcSnicm * Parameters for all mouse tracking escape sequences generated by xterm encode
1082*c7ef0cfcSnicm * numeric parameters in a single character as value+040. For example, ! is
1083*c7ef0cfcSnicm * 1.
1084*c7ef0cfcSnicm *
1085*c7ef0cfcSnicm * On button press or release, xterm sends ESC [ M CbCxCy. The low two bits of
1086*c7ef0cfcSnicm * Cb encode button information: 0=MB1 pressed, 1=MB2 pressed, 2=MB3 pressed,
1087*c7ef0cfcSnicm * 3=release. The upper bits encode what modifiers were down when the button
1088*c7ef0cfcSnicm * was pressed and are added together. 4=Shift, 8=Meta, 16=Control. Cx and Cy
1089*c7ef0cfcSnicm * are the x and y coordinates of the mouse event. The upper left corner is
1090*c7ef0cfcSnicm * (1,1).
1091*c7ef0cfcSnicm *
1092*c7ef0cfcSnicm * (End quote) By the time we get here, we've eaten the key prefix. FYI, the
1093*c7ef0cfcSnicm * loop below is necessary because mouse click info isn't guaranteed to present
1094*c7ef0cfcSnicm * as a single clist item.
1095*c7ef0cfcSnicm *
1096*c7ef0cfcSnicm * Wheel mice may return buttons 4 and 5 when the wheel is turned. We encode
1097*c7ef0cfcSnicm * those as button presses.
1098*c7ef0cfcSnicm */
1099*c7ef0cfcSnicm static bool
decode_xterm_X10(SCREEN * sp,MEVENT * eventp)1100*c7ef0cfcSnicm decode_xterm_X10(SCREEN *sp, MEVENT * eventp)
1101*c7ef0cfcSnicm {
1102*c7ef0cfcSnicm #define MAX_KBUF 3
1103*c7ef0cfcSnicm unsigned char kbuf[MAX_KBUF + 1];
1104*c7ef0cfcSnicm size_t grabbed;
1105*c7ef0cfcSnicm int res;
1106*c7ef0cfcSnicm bool result;
1107*c7ef0cfcSnicm
1108*c7ef0cfcSnicm _nc_set_read_thread(TRUE);
1109*c7ef0cfcSnicm for (grabbed = 0; grabbed < MAX_KBUF; grabbed += (size_t) res) {
1110*c7ef0cfcSnicm
1111*c7ef0cfcSnicm /* For VIO mouse we add extra bit 64 to disambiguate button-up. */
1112*c7ef0cfcSnicm res = (int) read(
1113*c7ef0cfcSnicm #if USE_EMX_MOUSE
1114*c7ef0cfcSnicm (M_FD(sp) >= 0) ? M_FD(sp) : sp->_ifd,
1115*c7ef0cfcSnicm #else
1116*c7ef0cfcSnicm sp->_ifd,
1117*c7ef0cfcSnicm #endif
1118*c7ef0cfcSnicm kbuf + grabbed, (size_t) (MAX_KBUF - (int) grabbed));
1119*c7ef0cfcSnicm if (res == -1)
1120*c7ef0cfcSnicm break;
1121*c7ef0cfcSnicm }
1122*c7ef0cfcSnicm _nc_set_read_thread(FALSE);
1123*c7ef0cfcSnicm kbuf[MAX_KBUF] = '\0';
1124*c7ef0cfcSnicm
1125*c7ef0cfcSnicm TR(TRACE_IEVENT,
1126*c7ef0cfcSnicm ("_nc_mouse_inline sees the following xterm data: '%s'", kbuf));
1127*c7ef0cfcSnicm
1128*c7ef0cfcSnicm /* there's only one mouse... */
1129*c7ef0cfcSnicm eventp->id = NORMAL_EVENT;
1130*c7ef0cfcSnicm
1131*c7ef0cfcSnicm result = decode_X10_bstate(sp, eventp, kbuf[0]);
113292dd1ec0Smillert
113392dd1ec0Smillert eventp->x = (kbuf[1] - ' ') - 1;
113492dd1ec0Smillert eventp->y = (kbuf[2] - ' ') - 1;
1135*c7ef0cfcSnicm
1136*c7ef0cfcSnicm return result;
1137*c7ef0cfcSnicm }
1138*c7ef0cfcSnicm
1139*c7ef0cfcSnicm #ifdef EXP_XTERM_1005
1140*c7ef0cfcSnicm /*
1141*c7ef0cfcSnicm * This is identical to X10/X11 responses except that there are two UTF-8
1142*c7ef0cfcSnicm * characters storing the ordinates instead of two bytes.
1143*c7ef0cfcSnicm */
1144*c7ef0cfcSnicm static bool
decode_xterm_1005(SCREEN * sp,MEVENT * eventp)1145*c7ef0cfcSnicm decode_xterm_1005(SCREEN *sp, MEVENT * eventp)
1146*c7ef0cfcSnicm {
1147*c7ef0cfcSnicm char kbuf[80];
1148*c7ef0cfcSnicm size_t grabbed;
1149*c7ef0cfcSnicm size_t limit = (sizeof(kbuf) - 1);
1150*c7ef0cfcSnicm unsigned coords[2];
1151*c7ef0cfcSnicm bool result;
1152*c7ef0cfcSnicm
1153*c7ef0cfcSnicm coords[0] = 0;
1154*c7ef0cfcSnicm coords[1] = 0;
1155*c7ef0cfcSnicm
1156*c7ef0cfcSnicm _nc_set_read_thread(TRUE);
1157*c7ef0cfcSnicm for (grabbed = 0; grabbed < limit;) {
1158*c7ef0cfcSnicm int res;
1159*c7ef0cfcSnicm
1160*c7ef0cfcSnicm res = (int) read(
1161*c7ef0cfcSnicm #if USE_EMX_MOUSE
1162*c7ef0cfcSnicm (M_FD(sp) >= 0) ? M_FD(sp) : sp->_ifd,
1163*c7ef0cfcSnicm #else
1164*c7ef0cfcSnicm sp->_ifd,
1165*c7ef0cfcSnicm #endif
1166*c7ef0cfcSnicm (kbuf + grabbed), (size_t) 1);
1167*c7ef0cfcSnicm if (res == -1)
1168*c7ef0cfcSnicm break;
1169*c7ef0cfcSnicm grabbed += (size_t) res;
1170*c7ef0cfcSnicm if (grabbed > 1) {
1171*c7ef0cfcSnicm size_t check = 1;
1172*c7ef0cfcSnicm int n;
1173*c7ef0cfcSnicm
1174*c7ef0cfcSnicm for (n = 0; n < 2; ++n) {
1175*c7ef0cfcSnicm int rc;
1176*c7ef0cfcSnicm
1177*c7ef0cfcSnicm if (check >= grabbed)
1178*c7ef0cfcSnicm break;
1179*c7ef0cfcSnicm rc = _nc_conv_to_utf32(&coords[n], kbuf + check, (unsigned)
1180*c7ef0cfcSnicm (grabbed - check));
1181*c7ef0cfcSnicm if (!rc)
1182*c7ef0cfcSnicm break;
1183*c7ef0cfcSnicm check += (size_t) rc;
1184*c7ef0cfcSnicm }
1185*c7ef0cfcSnicm if (n >= 2)
1186*c7ef0cfcSnicm break;
1187*c7ef0cfcSnicm }
1188*c7ef0cfcSnicm }
1189*c7ef0cfcSnicm _nc_set_read_thread(FALSE);
1190*c7ef0cfcSnicm
1191*c7ef0cfcSnicm TR(TRACE_IEVENT,
1192*c7ef0cfcSnicm ("_nc_mouse_inline sees the following xterm data: %s",
1193*c7ef0cfcSnicm _nc_visbufn(kbuf, (int) grabbed)));
1194*c7ef0cfcSnicm
1195*c7ef0cfcSnicm /* there's only one mouse... */
1196*c7ef0cfcSnicm eventp->id = NORMAL_EVENT;
1197*c7ef0cfcSnicm
1198*c7ef0cfcSnicm result = decode_X10_bstate(sp, eventp, UChar(kbuf[0]));
1199*c7ef0cfcSnicm
1200*c7ef0cfcSnicm eventp->x = (int) (coords[0] - ' ') - 1;
1201*c7ef0cfcSnicm eventp->y = (int) (coords[1] - ' ') - 1;
1202*c7ef0cfcSnicm
1203*c7ef0cfcSnicm return result;
1204*c7ef0cfcSnicm }
1205*c7ef0cfcSnicm #endif /* EXP_XTERM_1005 */
1206*c7ef0cfcSnicm
1207*c7ef0cfcSnicm /*
1208*c7ef0cfcSnicm * ECMA-48 section 5.4
1209*c7ef0cfcSnicm */
1210*c7ef0cfcSnicm #define isInter(c) ((c) >= 0x20 && (c) <= 0x2f)
1211*c7ef0cfcSnicm #define isParam(c) ((c) >= 0x30 && (c) <= 0x3f)
1212*c7ef0cfcSnicm #define isFinal(c) ((c) >= 0x40 && (c) <= 0x7e)
1213*c7ef0cfcSnicm
1214*c7ef0cfcSnicm #define MAX_PARAMS 9
1215*c7ef0cfcSnicm
1216*c7ef0cfcSnicm typedef struct {
1217*c7ef0cfcSnicm int nerror; /* nonzero if there are unexpected chars */
1218*c7ef0cfcSnicm int nparam; /* number of numeric parameters */
1219*c7ef0cfcSnicm int params[MAX_PARAMS];
1220*c7ef0cfcSnicm int final; /* the final-character */
1221*c7ef0cfcSnicm } SGR_DATA;
1222*c7ef0cfcSnicm
1223*c7ef0cfcSnicm static bool
read_SGR(SCREEN * sp,SGR_DATA * result)1224*c7ef0cfcSnicm read_SGR(SCREEN *sp, SGR_DATA * result)
1225*c7ef0cfcSnicm {
1226*c7ef0cfcSnicm char kbuf[80]; /* bigger than any possible mouse response */
1227*c7ef0cfcSnicm int grabbed = 0;
1228*c7ef0cfcSnicm int ch = 0;
1229*c7ef0cfcSnicm int now = -1;
1230*c7ef0cfcSnicm int marker = 1;
1231*c7ef0cfcSnicm
1232*c7ef0cfcSnicm memset(result, 0, sizeof(*result));
1233*c7ef0cfcSnicm _nc_set_read_thread(TRUE);
1234*c7ef0cfcSnicm
1235*c7ef0cfcSnicm do {
1236*c7ef0cfcSnicm int res;
1237*c7ef0cfcSnicm
1238*c7ef0cfcSnicm res = (int) read(
1239*c7ef0cfcSnicm #if USE_EMX_MOUSE
1240*c7ef0cfcSnicm (M_FD(sp) >= 0) ? M_FD(sp) : sp->_ifd,
1241*c7ef0cfcSnicm #else
1242*c7ef0cfcSnicm sp->_ifd,
1243*c7ef0cfcSnicm #endif
1244*c7ef0cfcSnicm (kbuf + grabbed), (size_t) 1);
1245*c7ef0cfcSnicm if (res == -1)
1246*c7ef0cfcSnicm break;
1247*c7ef0cfcSnicm if ((grabbed + MAX_KBUF) >= (int) sizeof(kbuf)) {
1248*c7ef0cfcSnicm result->nerror++;
1249*c7ef0cfcSnicm break;
1250*c7ef0cfcSnicm }
1251*c7ef0cfcSnicm ch = UChar(kbuf[grabbed]);
1252*c7ef0cfcSnicm kbuf[grabbed + 1] = 0;
1253*c7ef0cfcSnicm switch (ch) {
1254*c7ef0cfcSnicm case '0':
1255*c7ef0cfcSnicm case '1':
1256*c7ef0cfcSnicm case '2':
1257*c7ef0cfcSnicm case '3':
1258*c7ef0cfcSnicm case '4':
1259*c7ef0cfcSnicm case '5':
1260*c7ef0cfcSnicm case '6':
1261*c7ef0cfcSnicm case '7':
1262*c7ef0cfcSnicm case '8':
1263*c7ef0cfcSnicm case '9':
1264*c7ef0cfcSnicm if (marker) {
1265*c7ef0cfcSnicm ++now;
1266*c7ef0cfcSnicm result->nparam = (now + 1);
1267*c7ef0cfcSnicm }
1268*c7ef0cfcSnicm marker = 0;
1269*c7ef0cfcSnicm result->params[now] = (result->params[now] * 10) + (ch - '0');
1270*c7ef0cfcSnicm break;
1271*c7ef0cfcSnicm case ';':
1272*c7ef0cfcSnicm if (marker) {
1273*c7ef0cfcSnicm ++now;
1274*c7ef0cfcSnicm result->nparam = (now + 1);
1275*c7ef0cfcSnicm }
1276*c7ef0cfcSnicm marker = 1;
1277*c7ef0cfcSnicm break;
1278*c7ef0cfcSnicm default:
1279*c7ef0cfcSnicm if (ch < 32 || ch > 126) {
1280*c7ef0cfcSnicm /*
1281*c7ef0cfcSnicm * Technically other characters could be interspersed in the
1282*c7ef0cfcSnicm * response. Ignore those for now.
1283*c7ef0cfcSnicm */
1284*c7ef0cfcSnicm result->nerror++;
1285*c7ef0cfcSnicm continue;
1286*c7ef0cfcSnicm } else if (isFinal(ch)) {
1287*c7ef0cfcSnicm if (marker) {
1288*c7ef0cfcSnicm result->nparam++;
1289*c7ef0cfcSnicm }
1290*c7ef0cfcSnicm result->final = ch;
1291*c7ef0cfcSnicm } else {
1292*c7ef0cfcSnicm result->nerror++;
1293*c7ef0cfcSnicm }
1294*c7ef0cfcSnicm break;
1295*c7ef0cfcSnicm }
1296*c7ef0cfcSnicm ++grabbed;
1297*c7ef0cfcSnicm } while (!isFinal(ch));
1298*c7ef0cfcSnicm _nc_set_read_thread(FALSE);
1299*c7ef0cfcSnicm
1300*c7ef0cfcSnicm kbuf[++grabbed] = 0;
1301*c7ef0cfcSnicm TR(TRACE_IEVENT,
1302*c7ef0cfcSnicm ("_nc_mouse_inline sees the following xterm data: '%s'", kbuf));
1303*c7ef0cfcSnicm return (grabbed > 0) && (result->nerror == 0);
1304*c7ef0cfcSnicm }
1305*c7ef0cfcSnicm
1306*c7ef0cfcSnicm static bool
decode_xterm_SGR1006(SCREEN * sp,MEVENT * eventp)1307*c7ef0cfcSnicm decode_xterm_SGR1006(SCREEN *sp, MEVENT * eventp)
1308*c7ef0cfcSnicm {
1309*c7ef0cfcSnicm SGR_DATA data;
1310*c7ef0cfcSnicm bool result = FALSE;
1311*c7ef0cfcSnicm if (read_SGR(sp, &data)) {
1312*c7ef0cfcSnicm int b = data.params[0];
1313*c7ef0cfcSnicm int b3 = 1 + (b & 3);
1314*c7ef0cfcSnicm int wheel = ((b & 64) == 64);
1315*c7ef0cfcSnicm
1316*c7ef0cfcSnicm if (b >= 132) {
1317*c7ef0cfcSnicm b3 = MAX_BUTTONS + 1;
1318*c7ef0cfcSnicm } else if (b >= 128) {
1319*c7ef0cfcSnicm b3 = (b - 120); /* buttons 8-11 */
1320*c7ef0cfcSnicm } else if (b >= 64) {
1321*c7ef0cfcSnicm b3 = (b - 60); /* buttons 6-7 */
1322*c7ef0cfcSnicm }
1323*c7ef0cfcSnicm
1324*c7ef0cfcSnicm eventp->id = NORMAL_EVENT;
1325*c7ef0cfcSnicm if (data.final == 'M') {
1326*c7ef0cfcSnicm (void) handle_wheel(sp, eventp, b, wheel);
1327*c7ef0cfcSnicm } else if (b3 > MAX_BUTTONS) {
1328*c7ef0cfcSnicm eventp->bstate = REPORT_MOUSE_POSITION;
1329*c7ef0cfcSnicm } else {
1330*c7ef0cfcSnicm mmask_t pressed = (mmask_t) NCURSES_MOUSE_MASK(b3, NCURSES_BUTTON_PRESSED);
1331*c7ef0cfcSnicm mmask_t release = (mmask_t) NCURSES_MOUSE_MASK(b3, NCURSES_BUTTON_RELEASED);
1332*c7ef0cfcSnicm if (sp->_mouse_bstate & pressed) {
1333*c7ef0cfcSnicm eventp->bstate = release;
1334*c7ef0cfcSnicm sp->_mouse_bstate &= ~pressed;
1335*c7ef0cfcSnicm } else {
1336*c7ef0cfcSnicm eventp->bstate = REPORT_MOUSE_POSITION;
1337*c7ef0cfcSnicm }
1338*c7ef0cfcSnicm }
1339*c7ef0cfcSnicm if (b & 4) {
1340*c7ef0cfcSnicm eventp->bstate |= BUTTON_SHIFT;
1341*c7ef0cfcSnicm }
1342*c7ef0cfcSnicm if (b & 8) {
1343*c7ef0cfcSnicm eventp->bstate |= BUTTON_ALT;
1344*c7ef0cfcSnicm }
1345*c7ef0cfcSnicm if (b & 16) {
1346*c7ef0cfcSnicm eventp->bstate |= BUTTON_CTRL;
1347*c7ef0cfcSnicm }
1348*c7ef0cfcSnicm result = (eventp->bstate & REPORT_MOUSE_POSITION) ? TRUE : FALSE;
1349*c7ef0cfcSnicm eventp->x = (data.params[1] ? (data.params[1] - 1) : 0);
1350*c7ef0cfcSnicm eventp->y = (data.params[2] ? (data.params[2] - 1) : 0);
1351*c7ef0cfcSnicm }
1352*c7ef0cfcSnicm return result;
1353*c7ef0cfcSnicm }
1354*c7ef0cfcSnicm
1355*c7ef0cfcSnicm static bool
_nc_mouse_inline(SCREEN * sp)1356*c7ef0cfcSnicm _nc_mouse_inline(SCREEN *sp)
1357*c7ef0cfcSnicm /* mouse report received in the keyboard stream -- parse its info */
1358*c7ef0cfcSnicm {
1359*c7ef0cfcSnicm bool result = FALSE;
1360*c7ef0cfcSnicm MEVENT *eventp = sp->_mouse_eventp;
1361*c7ef0cfcSnicm
1362*c7ef0cfcSnicm TR(MY_TRACE, ("_nc_mouse_inline() called"));
1363*c7ef0cfcSnicm
1364*c7ef0cfcSnicm if (sp->_mouse_type == M_XTERM) {
1365*c7ef0cfcSnicm switch (sp->_mouse_format) {
1366*c7ef0cfcSnicm case MF_X10:
1367*c7ef0cfcSnicm result = decode_xterm_X10(sp, eventp);
1368*c7ef0cfcSnicm break;
1369*c7ef0cfcSnicm case MF_SGR1006:
1370*c7ef0cfcSnicm result = decode_xterm_SGR1006(sp, eventp);
1371*c7ef0cfcSnicm break;
1372*c7ef0cfcSnicm #ifdef EXP_XTERM_1005
1373*c7ef0cfcSnicm case MF_XTERM_1005:
1374*c7ef0cfcSnicm result = decode_xterm_1005(sp, eventp);
1375*c7ef0cfcSnicm break;
1376*c7ef0cfcSnicm #endif
1377*c7ef0cfcSnicm }
1378*c7ef0cfcSnicm
137923bb66c4Smillert TR(MY_TRACE,
138023bb66c4Smillert ("_nc_mouse_inline: primitive mouse-event %s has slot %ld",
138181d8c4e1Snicm _nc_tracemouse(sp, eventp),
138281d8c4e1Snicm (long) IndexEV(sp, eventp)));
138392dd1ec0Smillert
138492dd1ec0Smillert /* bump the next-free pointer into the circular list */
138581d8c4e1Snicm sp->_mouse_eventp = NEXT(eventp);
1386*c7ef0cfcSnicm
1387*c7ef0cfcSnicm if (!result) {
1388*c7ef0cfcSnicm /* If this event is from a wheel-mouse, treat it like position
1389*c7ef0cfcSnicm * reports and avoid waiting for the release-events which will
1390*c7ef0cfcSnicm * never come.
1391*c7ef0cfcSnicm */
1392*c7ef0cfcSnicm if (eventp->bstate & BUTTON_PRESSED) {
1393*c7ef0cfcSnicm int b;
1394*c7ef0cfcSnicm
1395*c7ef0cfcSnicm for (b = 4; b <= MAX_BUTTONS; ++b) {
1396*c7ef0cfcSnicm if ((eventp->bstate & MASK_PRESS(b))) {
1397*c7ef0cfcSnicm result = TRUE;
1398*c7ef0cfcSnicm break;
1399*c7ef0cfcSnicm }
1400*c7ef0cfcSnicm }
1401*c7ef0cfcSnicm }
1402*c7ef0cfcSnicm }
140392dd1ec0Smillert }
140492dd1ec0Smillert
140581d8c4e1Snicm return (result);
140692dd1ec0Smillert }
140792dd1ec0Smillert
140823bb66c4Smillert static void
mouse_activate(SCREEN * sp,int on)1409*c7ef0cfcSnicm mouse_activate(SCREEN *sp, int on)
141092dd1ec0Smillert {
1411*c7ef0cfcSnicm T((T_CALLED("mouse_activate(%p,%s)"),
1412*c7ef0cfcSnicm (void *) SP_PARM, on ? "on" : "off"));
1413*c7ef0cfcSnicm
141481d8c4e1Snicm if (!on && !sp->_mouse_initialized)
1415*c7ef0cfcSnicm returnVoid;
141692dd1ec0Smillert
141781d8c4e1Snicm if (!_nc_mouse_init(sp))
1418*c7ef0cfcSnicm returnVoid;
141992dd1ec0Smillert
142092dd1ec0Smillert if (on) {
1421*c7ef0cfcSnicm sp->_mouse_bstate = 0;
142281d8c4e1Snicm switch (sp->_mouse_type) {
142392dd1ec0Smillert case M_XTERM:
142491421ef5Smillert #if NCURSES_EXT_FUNCS
1425*c7ef0cfcSnicm NCURSES_SP_NAME(keyok) (NCURSES_SP_ARGx KEY_MOUSE, on);
142692dd1ec0Smillert #endif
142781d8c4e1Snicm enable_xterm_mouse(sp, 1);
142892dd1ec0Smillert break;
142992dd1ec0Smillert #if USE_GPM_SUPPORT
143092dd1ec0Smillert case M_GPM:
143181d8c4e1Snicm if (enable_gpm_mouse(sp, TRUE)) {
143281d8c4e1Snicm sp->_mouse_fd = *(my_gpm_fd);
143381d8c4e1Snicm T(("GPM mouse_fd %d", sp->_mouse_fd));
143481d8c4e1Snicm }
143592dd1ec0Smillert break;
143692dd1ec0Smillert #endif
143781d8c4e1Snicm #if USE_SYSMOUSE
143881d8c4e1Snicm case M_SYSMOUSE:
143981d8c4e1Snicm signal(SIGUSR2, handle_sysmouse);
144081d8c4e1Snicm sp->_mouse_active = TRUE;
144181d8c4e1Snicm break;
144281d8c4e1Snicm #endif
1443*c7ef0cfcSnicm #ifdef USE_TERM_DRIVER
1444*c7ef0cfcSnicm case M_TERM_DRIVER:
1445*c7ef0cfcSnicm enable_win32_mouse(sp, TRUE);
1446*c7ef0cfcSnicm break;
1447*c7ef0cfcSnicm #endif
144881d8c4e1Snicm case M_NONE:
1449*c7ef0cfcSnicm returnVoid;
1450*c7ef0cfcSnicm default:
1451*c7ef0cfcSnicm T(("unexpected mouse mode"));
1452*c7ef0cfcSnicm break;
145392dd1ec0Smillert }
145492dd1ec0Smillert /* Make runtime binding to cut down on object size of applications that
145592dd1ec0Smillert * do not use the mouse (e.g., 'clear').
145692dd1ec0Smillert */
1457*c7ef0cfcSnicm /* *INDENT-EQLS* */
145881d8c4e1Snicm sp->_mouse_event = _nc_mouse_event;
145981d8c4e1Snicm sp->_mouse_inline = _nc_mouse_inline;
146081d8c4e1Snicm sp->_mouse_parse = _nc_mouse_parse;
146181d8c4e1Snicm sp->_mouse_resume = _nc_mouse_resume;
146281d8c4e1Snicm sp->_mouse_wrap = _nc_mouse_wrap;
146392dd1ec0Smillert } else {
146492dd1ec0Smillert
146581d8c4e1Snicm switch (sp->_mouse_type) {
146692dd1ec0Smillert case M_XTERM:
146781d8c4e1Snicm enable_xterm_mouse(sp, 0);
146892dd1ec0Smillert break;
146992dd1ec0Smillert #if USE_GPM_SUPPORT
147092dd1ec0Smillert case M_GPM:
147181d8c4e1Snicm enable_gpm_mouse(sp, FALSE);
147292dd1ec0Smillert break;
147392dd1ec0Smillert #endif
147481d8c4e1Snicm #if USE_SYSMOUSE
147581d8c4e1Snicm case M_SYSMOUSE:
147681d8c4e1Snicm signal(SIGUSR2, SIG_IGN);
147781d8c4e1Snicm sp->_mouse_active = FALSE;
147881d8c4e1Snicm break;
147981d8c4e1Snicm #endif
1480*c7ef0cfcSnicm #ifdef USE_TERM_DRIVER
1481*c7ef0cfcSnicm case M_TERM_DRIVER:
1482*c7ef0cfcSnicm enable_win32_mouse(sp, FALSE);
1483*c7ef0cfcSnicm break;
1484*c7ef0cfcSnicm #endif
148581d8c4e1Snicm case M_NONE:
1486*c7ef0cfcSnicm returnVoid;
1487*c7ef0cfcSnicm default:
1488*c7ef0cfcSnicm T(("unexpected mouse mode"));
1489*c7ef0cfcSnicm break;
149092dd1ec0Smillert }
149192dd1ec0Smillert }
1492*c7ef0cfcSnicm NCURSES_SP_NAME(_nc_flush) (NCURSES_SP_ARG);
1493*c7ef0cfcSnicm returnVoid;
149492dd1ec0Smillert }
149592dd1ec0Smillert
149692dd1ec0Smillert /**************************************************************************
149792dd1ec0Smillert *
149892dd1ec0Smillert * Device-independent code
149992dd1ec0Smillert *
150092dd1ec0Smillert **************************************************************************/
150192dd1ec0Smillert
150223bb66c4Smillert static bool
_nc_mouse_parse(SCREEN * sp,int runcount)150381d8c4e1Snicm _nc_mouse_parse(SCREEN *sp, int runcount)
150492dd1ec0Smillert /* parse a run of atomic mouse events into a gesture */
150592dd1ec0Smillert {
150681d8c4e1Snicm MEVENT *eventp = sp->_mouse_eventp;
1507*c7ef0cfcSnicm MEVENT *next, *ep;
1508*c7ef0cfcSnicm MEVENT *first_valid = NULL;
1509*c7ef0cfcSnicm MEVENT *first_invalid = NULL;
151092dd1ec0Smillert int n;
151181d8c4e1Snicm int b;
151292dd1ec0Smillert bool merge;
1513*c7ef0cfcSnicm bool endLoop;
151492dd1ec0Smillert
151592dd1ec0Smillert TR(MY_TRACE, ("_nc_mouse_parse(%d) called", runcount));
151692dd1ec0Smillert
151792dd1ec0Smillert /*
151892dd1ec0Smillert * When we enter this routine, the event list next-free pointer
151992dd1ec0Smillert * points just past a run of mouse events that we know were separated
152092dd1ec0Smillert * in time by less than the critical click interval. The job of this
152181d8c4e1Snicm * routine is to collapse this run into a single higher-level event
152292dd1ec0Smillert * or gesture.
152392dd1ec0Smillert *
152492dd1ec0Smillert * We accomplish this in two passes. The first pass merges press/release
152592dd1ec0Smillert * pairs into click events. The second merges runs of click events into
152692dd1ec0Smillert * double or triple-click events.
152792dd1ec0Smillert *
152892dd1ec0Smillert * It's possible that the run may not resolve to a single event (for
152992dd1ec0Smillert * example, if the user quadruple-clicks). If so, leading events
1530*c7ef0cfcSnicm * in the run are ignored if user does not call getmouse in a loop (getting
1531*c7ef0cfcSnicm * them from newest to older).
153292dd1ec0Smillert *
153392dd1ec0Smillert * Note that this routine is independent of the format of the specific
153492dd1ec0Smillert * format of the pointing-device's reports. We can use it to parse
153592dd1ec0Smillert * gestures on anything that reports press/release events on a per-
153692dd1ec0Smillert * button basis, as long as the device-dependent mouse code puts stuff
153792dd1ec0Smillert * on the queue in MEVENT format.
153892dd1ec0Smillert */
153992dd1ec0Smillert
1540*c7ef0cfcSnicm /*
1541*c7ef0cfcSnicm * Reset all events that were not set, in case the user sometimes calls
1542*c7ef0cfcSnicm * getmouse only once and other times until there are no more events in
1543*c7ef0cfcSnicm * queue.
1544*c7ef0cfcSnicm *
1545*c7ef0cfcSnicm * This also allows reaching the beginning of the run.
1546*c7ef0cfcSnicm */
1547*c7ef0cfcSnicm ep = eventp;
1548*c7ef0cfcSnicm for (n = runcount; n < EV_MAX; n++) {
1549*c7ef0cfcSnicm Invalidate(ep);
1550*c7ef0cfcSnicm ep = NEXT(ep);
155192dd1ec0Smillert }
155292dd1ec0Smillert
155392dd1ec0Smillert #ifdef TRACE
155481d8c4e1Snicm if (USE_TRACEF(TRACE_IEVENT)) {
155581d8c4e1Snicm _trace_slot(sp, "before mouse press/release merge:");
155692dd1ec0Smillert _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
1557*c7ef0cfcSnicm RunParams(sp, eventp, ep),
155892dd1ec0Smillert runcount);
155981d8c4e1Snicm _nc_unlock_global(tracef);
156092dd1ec0Smillert }
156192dd1ec0Smillert #endif /* TRACE */
156292dd1ec0Smillert
156392dd1ec0Smillert /* first pass; merge press/release pairs */
1564*c7ef0cfcSnicm endLoop = FALSE;
1565*c7ef0cfcSnicm while (!endLoop) {
1566*c7ef0cfcSnicm next = NEXT(ep);
1567*c7ef0cfcSnicm if (next == eventp) {
1568*c7ef0cfcSnicm /* Will end the loop, but compact before */
1569*c7ef0cfcSnicm endLoop = TRUE;
1570*c7ef0cfcSnicm } else {
157181d8c4e1Snicm
157281d8c4e1Snicm #define MASK_CHANGED(x) (!(ep->bstate & MASK_PRESS(x)) \
157381d8c4e1Snicm == !(next->bstate & MASK_RELEASE(x)))
157481d8c4e1Snicm
1575*c7ef0cfcSnicm if (ValidEvent(ep) && ValidEvent(next)
1576*c7ef0cfcSnicm && ep->x == next->x && ep->y == next->y
157781d8c4e1Snicm && (ep->bstate & BUTTON_PRESSED)
1578*c7ef0cfcSnicm && (!(next->bstate & BUTTON_PRESSED))) {
1579*c7ef0cfcSnicm bool changed = TRUE;
1580*c7ef0cfcSnicm
158181d8c4e1Snicm for (b = 1; b <= MAX_BUTTONS; ++b) {
1582*c7ef0cfcSnicm if (!MASK_CHANGED(b)) {
1583*c7ef0cfcSnicm changed = FALSE;
1584*c7ef0cfcSnicm break;
1585*c7ef0cfcSnicm }
1586*c7ef0cfcSnicm }
1587*c7ef0cfcSnicm
1588*c7ef0cfcSnicm if (changed) {
1589*c7ef0cfcSnicm merge = FALSE;
1590*c7ef0cfcSnicm for (b = 1; b <= MAX_BUTTONS; ++b) {
1591*c7ef0cfcSnicm if ((sp->_mouse_mask2 & MASK_CLICK(b))
159281d8c4e1Snicm && (ep->bstate & MASK_PRESS(b))) {
1593*c7ef0cfcSnicm next->bstate &= ~MASK_RELEASE(b);
1594*c7ef0cfcSnicm next->bstate |= MASK_CLICK(b);
159592dd1ec0Smillert merge = TRUE;
159692dd1ec0Smillert }
159792dd1ec0Smillert }
1598*c7ef0cfcSnicm if (merge) {
1599*c7ef0cfcSnicm Invalidate(ep);
160092dd1ec0Smillert }
160192dd1ec0Smillert }
1602*c7ef0cfcSnicm }
1603*c7ef0cfcSnicm }
160492dd1ec0Smillert
1605*c7ef0cfcSnicm /* Compact valid events */
1606*c7ef0cfcSnicm if (!ValidEvent(ep)) {
1607*c7ef0cfcSnicm if ((first_valid != NULL) && (first_invalid == NULL)) {
1608*c7ef0cfcSnicm first_invalid = ep;
1609*c7ef0cfcSnicm }
1610*c7ef0cfcSnicm } else {
1611*c7ef0cfcSnicm if (first_valid == NULL) {
1612*c7ef0cfcSnicm first_valid = ep;
1613*c7ef0cfcSnicm } else if (first_invalid != NULL) {
1614*c7ef0cfcSnicm *first_invalid = *ep;
1615*c7ef0cfcSnicm Invalidate(ep);
1616*c7ef0cfcSnicm first_invalid = NEXT(first_invalid);
1617*c7ef0cfcSnicm }
1618*c7ef0cfcSnicm }
1619*c7ef0cfcSnicm
1620*c7ef0cfcSnicm ep = next;
1621*c7ef0cfcSnicm }
1622*c7ef0cfcSnicm
1623*c7ef0cfcSnicm if (first_invalid != NULL) {
1624*c7ef0cfcSnicm eventp = first_invalid;
1625*c7ef0cfcSnicm }
162692dd1ec0Smillert #ifdef TRACE
162781d8c4e1Snicm if (USE_TRACEF(TRACE_IEVENT)) {
162881d8c4e1Snicm _trace_slot(sp, "before mouse click merge:");
1629*c7ef0cfcSnicm if (first_valid == NULL) {
1630*c7ef0cfcSnicm _tracef("_nc_mouse_parse: no valid event");
1631*c7ef0cfcSnicm } else {
163292dd1ec0Smillert _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
1633*c7ef0cfcSnicm RunParams(sp, eventp, first_valid),
163492dd1ec0Smillert runcount);
163581d8c4e1Snicm _nc_unlock_global(tracef);
163692dd1ec0Smillert }
1637*c7ef0cfcSnicm }
163892dd1ec0Smillert #endif /* TRACE */
163992dd1ec0Smillert
164092dd1ec0Smillert /*
1641*c7ef0cfcSnicm * Second pass; merge click runs. We merge click events forward in the
1642*c7ef0cfcSnicm * queue. For example, double click can be changed to triple click.
164392dd1ec0Smillert *
164492dd1ec0Smillert * NOTE: There is a problem with this design! If the application
164592dd1ec0Smillert * allows enough click events to pile up in the circular queue so
164692dd1ec0Smillert * they wrap around, it will cheerfully merge the newest forward
164792dd1ec0Smillert * into the oldest, creating a bogus doubleclick and confusing
164892dd1ec0Smillert * the queue-traversal logic rather badly. Generally this won't
164992dd1ec0Smillert * happen, because calling getmouse() marks old events invalid and
165092dd1ec0Smillert * ineligible for merges. The true solution to this problem would
165192dd1ec0Smillert * be to timestamp each MEVENT and perform the obvious sanity check,
165292dd1ec0Smillert * but the timer element would have to have sub-second resolution,
165392dd1ec0Smillert * which would get us into portability trouble.
165492dd1ec0Smillert */
1655*c7ef0cfcSnicm first_invalid = NULL;
1656*c7ef0cfcSnicm endLoop = (first_valid == NULL);
1657*c7ef0cfcSnicm ep = first_valid;
1658*c7ef0cfcSnicm while (!endLoop) {
1659*c7ef0cfcSnicm next = NEXT(ep);
166092dd1ec0Smillert
1661*c7ef0cfcSnicm if (next == eventp) {
1662*c7ef0cfcSnicm /* Will end the loop, but check event type and compact before */
1663*c7ef0cfcSnicm endLoop = TRUE;
1664*c7ef0cfcSnicm } else if (!ValidEvent(next)) {
166592dd1ec0Smillert continue;
1666*c7ef0cfcSnicm } else {
166792dd1ec0Smillert /* merge click events forward */
166881d8c4e1Snicm if ((ep->bstate & BUTTON_CLICKED)
1669*c7ef0cfcSnicm && (next->bstate & BUTTON_CLICKED)) {
1670*c7ef0cfcSnicm merge = FALSE;
167181d8c4e1Snicm for (b = 1; b <= MAX_BUTTONS; ++b) {
1672*c7ef0cfcSnicm if ((sp->_mouse_mask2 & MASK_DOUBLE_CLICK(b))
1673*c7ef0cfcSnicm && (ep->bstate & MASK_CLICK(b))
1674*c7ef0cfcSnicm && (next->bstate & MASK_CLICK(b))) {
1675*c7ef0cfcSnicm next->bstate &= ~MASK_CLICK(b);
1676*c7ef0cfcSnicm next->bstate |= MASK_DOUBLE_CLICK(b);
167792dd1ec0Smillert merge = TRUE;
167892dd1ec0Smillert }
167992dd1ec0Smillert }
1680*c7ef0cfcSnicm if (merge) {
1681*c7ef0cfcSnicm Invalidate(ep);
1682*c7ef0cfcSnicm }
168392dd1ec0Smillert }
168492dd1ec0Smillert
168592dd1ec0Smillert /* merge double-click events forward */
168681d8c4e1Snicm if ((ep->bstate & BUTTON_DOUBLE_CLICKED)
1687*c7ef0cfcSnicm && (next->bstate & BUTTON_CLICKED)) {
1688*c7ef0cfcSnicm merge = FALSE;
168981d8c4e1Snicm for (b = 1; b <= MAX_BUTTONS; ++b) {
1690*c7ef0cfcSnicm if ((sp->_mouse_mask2 & MASK_TRIPLE_CLICK(b))
1691*c7ef0cfcSnicm && (ep->bstate & MASK_DOUBLE_CLICK(b))
1692*c7ef0cfcSnicm && (next->bstate & MASK_CLICK(b))) {
1693*c7ef0cfcSnicm next->bstate &= ~MASK_CLICK(b);
1694*c7ef0cfcSnicm next->bstate |= MASK_TRIPLE_CLICK(b);
169592dd1ec0Smillert merge = TRUE;
169692dd1ec0Smillert }
169792dd1ec0Smillert }
1698*c7ef0cfcSnicm if (merge) {
1699*c7ef0cfcSnicm Invalidate(ep);
170092dd1ec0Smillert }
170192dd1ec0Smillert }
1702*c7ef0cfcSnicm }
1703*c7ef0cfcSnicm
1704*c7ef0cfcSnicm /* Discard event if it does not match event mask */
1705*c7ef0cfcSnicm if (!(ep->bstate & sp->_mouse_mask2)) {
1706*c7ef0cfcSnicm Invalidate(ep);
1707*c7ef0cfcSnicm }
1708*c7ef0cfcSnicm
1709*c7ef0cfcSnicm /* Compact valid events */
1710*c7ef0cfcSnicm if (!ValidEvent(ep)) {
1711*c7ef0cfcSnicm if (ep == first_valid) {
1712*c7ef0cfcSnicm first_valid = next;
1713*c7ef0cfcSnicm } else if (first_invalid == NULL) {
1714*c7ef0cfcSnicm first_invalid = ep;
1715*c7ef0cfcSnicm }
1716*c7ef0cfcSnicm } else if (first_invalid != NULL) {
1717*c7ef0cfcSnicm *first_invalid = *ep;
1718*c7ef0cfcSnicm Invalidate(ep);
1719*c7ef0cfcSnicm first_invalid = NEXT(first_invalid);
1720*c7ef0cfcSnicm }
1721*c7ef0cfcSnicm
1722*c7ef0cfcSnicm ep = next;
1723*c7ef0cfcSnicm }
1724*c7ef0cfcSnicm
1725*c7ef0cfcSnicm if (first_invalid == NULL) {
1726*c7ef0cfcSnicm first_invalid = eventp;
1727*c7ef0cfcSnicm }
1728*c7ef0cfcSnicm sp->_mouse_eventp = first_invalid;
172992dd1ec0Smillert
173092dd1ec0Smillert #ifdef TRACE
1731*c7ef0cfcSnicm if (first_valid != NULL) {
173281d8c4e1Snicm if (USE_TRACEF(TRACE_IEVENT)) {
173381d8c4e1Snicm _trace_slot(sp, "after mouse event queue compaction:");
173492dd1ec0Smillert _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d",
1735*c7ef0cfcSnicm RunParams(sp, first_invalid, first_valid),
173692dd1ec0Smillert runcount);
173781d8c4e1Snicm _nc_unlock_global(tracef);
173892dd1ec0Smillert }
1739*c7ef0cfcSnicm for (ep = first_valid; ep != first_invalid; ep = NEXT(ep)) {
1740*c7ef0cfcSnicm if (ValidEvent(ep))
174123bb66c4Smillert TR(MY_TRACE,
174223bb66c4Smillert ("_nc_mouse_parse: returning composite mouse event %s at slot %ld",
174381d8c4e1Snicm _nc_tracemouse(sp, ep),
174481d8c4e1Snicm (long) IndexEV(sp, ep)));
1745*c7ef0cfcSnicm }
1746*c7ef0cfcSnicm }
174792dd1ec0Smillert #endif /* TRACE */
174892dd1ec0Smillert
174992dd1ec0Smillert /* after all this, do we have a valid event? */
1750*c7ef0cfcSnicm ep = PREV(first_invalid);
1751*c7ef0cfcSnicm return ValidEvent(ep) && ((ep->bstate & sp->_mouse_mask) != 0);
175292dd1ec0Smillert }
175392dd1ec0Smillert
175423bb66c4Smillert static void
_nc_mouse_wrap(SCREEN * sp)175581d8c4e1Snicm _nc_mouse_wrap(SCREEN *sp)
175692dd1ec0Smillert /* release mouse -- called by endwin() before shellout/exit */
175792dd1ec0Smillert {
175892dd1ec0Smillert TR(MY_TRACE, ("_nc_mouse_wrap() called"));
175992dd1ec0Smillert
176081d8c4e1Snicm switch (sp->_mouse_type) {
176192dd1ec0Smillert case M_XTERM:
176281d8c4e1Snicm if (sp->_mouse_mask)
176381d8c4e1Snicm mouse_activate(sp, FALSE);
176492dd1ec0Smillert break;
176592dd1ec0Smillert #if USE_GPM_SUPPORT
176692dd1ec0Smillert /* GPM: pass all mouse events to next client */
176792dd1ec0Smillert case M_GPM:
176881d8c4e1Snicm if (sp->_mouse_mask)
176981d8c4e1Snicm mouse_activate(sp, FALSE);
177092dd1ec0Smillert break;
177192dd1ec0Smillert #endif
177281d8c4e1Snicm #if USE_SYSMOUSE
177381d8c4e1Snicm case M_SYSMOUSE:
177481d8c4e1Snicm mouse_activate(sp, FALSE);
177581d8c4e1Snicm break;
177681d8c4e1Snicm #endif
1777*c7ef0cfcSnicm #ifdef USE_TERM_DRIVER
1778*c7ef0cfcSnicm case M_TERM_DRIVER:
1779*c7ef0cfcSnicm mouse_activate(sp, FALSE);
1780*c7ef0cfcSnicm break;
1781*c7ef0cfcSnicm #endif
178281d8c4e1Snicm case M_NONE:
178381d8c4e1Snicm break;
178492dd1ec0Smillert }
178592dd1ec0Smillert }
178692dd1ec0Smillert
178723bb66c4Smillert static void
_nc_mouse_resume(SCREEN * sp)178881d8c4e1Snicm _nc_mouse_resume(SCREEN *sp)
178992dd1ec0Smillert /* re-connect to mouse -- called by doupdate() after shellout */
179092dd1ec0Smillert {
179192dd1ec0Smillert TR(MY_TRACE, ("_nc_mouse_resume() called"));
179292dd1ec0Smillert
179381d8c4e1Snicm switch (sp->_mouse_type) {
179481d8c4e1Snicm case M_XTERM:
179592dd1ec0Smillert /* xterm: re-enable reporting */
179681d8c4e1Snicm if (sp->_mouse_mask)
179781d8c4e1Snicm mouse_activate(sp, TRUE);
179881d8c4e1Snicm break;
179992dd1ec0Smillert
180081d8c4e1Snicm #if USE_GPM_SUPPORT
180181d8c4e1Snicm case M_GPM:
180292dd1ec0Smillert /* GPM: reclaim our event set */
180381d8c4e1Snicm if (sp->_mouse_mask)
180481d8c4e1Snicm mouse_activate(sp, TRUE);
180581d8c4e1Snicm break;
180681d8c4e1Snicm #endif
180781d8c4e1Snicm
180881d8c4e1Snicm #if USE_SYSMOUSE
180981d8c4e1Snicm case M_SYSMOUSE:
181081d8c4e1Snicm mouse_activate(sp, TRUE);
181181d8c4e1Snicm break;
181281d8c4e1Snicm #endif
1813*c7ef0cfcSnicm
1814*c7ef0cfcSnicm #ifdef USE_TERM_DRIVER
1815*c7ef0cfcSnicm case M_TERM_DRIVER:
1816*c7ef0cfcSnicm mouse_activate(sp, TRUE);
1817*c7ef0cfcSnicm break;
1818*c7ef0cfcSnicm #endif
1819*c7ef0cfcSnicm
182081d8c4e1Snicm case M_NONE:
182181d8c4e1Snicm break;
182281d8c4e1Snicm }
182392dd1ec0Smillert }
182492dd1ec0Smillert
182592dd1ec0Smillert /**************************************************************************
182692dd1ec0Smillert *
182792dd1ec0Smillert * Mouse interface entry points for the API
182892dd1ec0Smillert *
182992dd1ec0Smillert **************************************************************************/
183092dd1ec0Smillert
1831*c7ef0cfcSnicm NCURSES_EXPORT(int)
NCURSES_SP_NAME(getmouse)1832*c7ef0cfcSnicm NCURSES_SP_NAME(getmouse) (NCURSES_SP_DCLx MEVENT * aevent)
183392dd1ec0Smillert {
1834*c7ef0cfcSnicm int result = ERR;
1835*c7ef0cfcSnicm MEVENT *eventp;
183692dd1ec0Smillert
1837*c7ef0cfcSnicm T((T_CALLED("getmouse(%p,%p)"), (void *) SP_PARM, (void *) aevent));
1838*c7ef0cfcSnicm
1839*c7ef0cfcSnicm if ((aevent != 0) &&
1840*c7ef0cfcSnicm (SP_PARM != 0) &&
1841*c7ef0cfcSnicm (SP_PARM->_mouse_type != M_NONE) &&
1842*c7ef0cfcSnicm (eventp = SP_PARM->_mouse_eventp) != 0) {
184392dd1ec0Smillert /* compute the current-event pointer */
184492dd1ec0Smillert MEVENT *prev = PREV(eventp);
184592dd1ec0Smillert
1846*c7ef0cfcSnicm /*
1847*c7ef0cfcSnicm * Discard events not matching mask (there could be still some if
1848*c7ef0cfcSnicm * _nc_mouse_parse was not called, e.g., when _nc_mouse_inline returns
1849*c7ef0cfcSnicm * false).
1850*c7ef0cfcSnicm */
1851*c7ef0cfcSnicm while (ValidEvent(prev) && (!(prev->bstate & SP_PARM->_mouse_mask2))) {
1852*c7ef0cfcSnicm Invalidate(prev);
1853*c7ef0cfcSnicm prev = PREV(prev);
1854*c7ef0cfcSnicm }
1855*c7ef0cfcSnicm if (ValidEvent(prev)) {
185692dd1ec0Smillert /* copy the event we find there */
185792dd1ec0Smillert *aevent = *prev;
185892dd1ec0Smillert
185992dd1ec0Smillert TR(TRACE_IEVENT, ("getmouse: returning event %s from slot %ld",
1860*c7ef0cfcSnicm _nc_tracemouse(SP_PARM, prev),
1861*c7ef0cfcSnicm (long) IndexEV(SP_PARM, prev)));
186292dd1ec0Smillert
1863*c7ef0cfcSnicm Invalidate(prev); /* so the queue slot becomes free */
1864*c7ef0cfcSnicm SP_PARM->_mouse_eventp = prev;
1865*c7ef0cfcSnicm result = OK;
1866*c7ef0cfcSnicm } else {
1867*c7ef0cfcSnicm /* Reset the provided event */
1868*c7ef0cfcSnicm aevent->bstate = 0;
1869*c7ef0cfcSnicm Invalidate(aevent);
1870*c7ef0cfcSnicm aevent->x = 0;
1871*c7ef0cfcSnicm aevent->y = 0;
1872*c7ef0cfcSnicm aevent->z = 0;
187392dd1ec0Smillert }
1874*c7ef0cfcSnicm }
1875*c7ef0cfcSnicm returnCode(result);
187692dd1ec0Smillert }
187792dd1ec0Smillert
1878*c7ef0cfcSnicm #if NCURSES_SP_FUNCS
187981d8c4e1Snicm /* grab a copy of the current mouse event */
188084af20ceSmillert NCURSES_EXPORT(int)
getmouse(MEVENT * aevent)188181d8c4e1Snicm getmouse(MEVENT * aevent)
188292dd1ec0Smillert {
1883*c7ef0cfcSnicm return NCURSES_SP_NAME(getmouse) (CURRENT_SCREEN, aevent);
188481d8c4e1Snicm }
1885*c7ef0cfcSnicm #endif
188681d8c4e1Snicm
1887*c7ef0cfcSnicm NCURSES_EXPORT(int)
NCURSES_SP_NAME(ungetmouse)1888*c7ef0cfcSnicm NCURSES_SP_NAME(ungetmouse) (NCURSES_SP_DCLx MEVENT * aevent)
188981d8c4e1Snicm {
189081d8c4e1Snicm int result = ERR;
1891*c7ef0cfcSnicm MEVENT *eventp;
189281d8c4e1Snicm
1893*c7ef0cfcSnicm T((T_CALLED("ungetmouse(%p,%p)"), (void *) SP_PARM, (void *) aevent));
189481d8c4e1Snicm
1895*c7ef0cfcSnicm if (aevent != 0 &&
1896*c7ef0cfcSnicm SP_PARM != 0 &&
1897*c7ef0cfcSnicm (eventp = SP_PARM->_mouse_eventp) != 0) {
189881d8c4e1Snicm
189992dd1ec0Smillert /* stick the given event in the next-free slot */
190092dd1ec0Smillert *eventp = *aevent;
190192dd1ec0Smillert
190292dd1ec0Smillert /* bump the next-free pointer into the circular list */
1903*c7ef0cfcSnicm SP_PARM->_mouse_eventp = NEXT(eventp);
190492dd1ec0Smillert
190592dd1ec0Smillert /* push back the notification event on the keyboard queue */
1906*c7ef0cfcSnicm result = NCURSES_SP_NAME(ungetch) (NCURSES_SP_ARGx KEY_MOUSE);
190781d8c4e1Snicm }
190881d8c4e1Snicm returnCode(result);
190981d8c4e1Snicm }
191081d8c4e1Snicm
1911*c7ef0cfcSnicm #if NCURSES_SP_FUNCS
191281d8c4e1Snicm /* enqueue a synthesized mouse event to be seen by the next wgetch() */
191381d8c4e1Snicm NCURSES_EXPORT(int)
ungetmouse(MEVENT * aevent)191481d8c4e1Snicm ungetmouse(MEVENT * aevent)
191581d8c4e1Snicm {
1916*c7ef0cfcSnicm return NCURSES_SP_NAME(ungetmouse) (CURRENT_SCREEN, aevent);
191792dd1ec0Smillert }
1918*c7ef0cfcSnicm #endif
191992dd1ec0Smillert
192084af20ceSmillert NCURSES_EXPORT(mmask_t)
NCURSES_SP_NAME(mousemask)1921*c7ef0cfcSnicm NCURSES_SP_NAME(mousemask) (NCURSES_SP_DCLx mmask_t newmask, mmask_t * oldmask)
192292dd1ec0Smillert /* set the mouse event mask */
192392dd1ec0Smillert {
192492dd1ec0Smillert mmask_t result = 0;
192592dd1ec0Smillert
1926*c7ef0cfcSnicm T((T_CALLED("mousemask(%p,%#lx,%p)"),
1927*c7ef0cfcSnicm (void *) SP_PARM,
1928*c7ef0cfcSnicm (unsigned long) newmask,
1929*c7ef0cfcSnicm (void *) oldmask));
193092dd1ec0Smillert
1931*c7ef0cfcSnicm if (SP_PARM != 0) {
193292dd1ec0Smillert if (oldmask)
1933*c7ef0cfcSnicm *oldmask = SP_PARM->_mouse_mask;
193492dd1ec0Smillert
1935*c7ef0cfcSnicm if (newmask || SP_PARM->_mouse_initialized) {
1936*c7ef0cfcSnicm _nc_mouse_init(SP_PARM);
1937*c7ef0cfcSnicm
1938*c7ef0cfcSnicm if (SP_PARM->_mouse_type != M_NONE) {
1939*c7ef0cfcSnicm int b;
1940*c7ef0cfcSnicm
194181d8c4e1Snicm result = newmask &
194281d8c4e1Snicm (REPORT_MOUSE_POSITION
194381d8c4e1Snicm | BUTTON_ALT
194481d8c4e1Snicm | BUTTON_CTRL
194581d8c4e1Snicm | BUTTON_SHIFT
194681d8c4e1Snicm | BUTTON_PRESSED
194781d8c4e1Snicm | BUTTON_RELEASED
194881d8c4e1Snicm | BUTTON_CLICKED
194981d8c4e1Snicm | BUTTON_DOUBLE_CLICKED
195081d8c4e1Snicm | BUTTON_TRIPLE_CLICKED);
195192dd1ec0Smillert
1952*c7ef0cfcSnicm mouse_activate(SP_PARM, (bool) (result != 0));
195392dd1ec0Smillert
1954*c7ef0cfcSnicm SP_PARM->_mouse_mask = result;
1955*c7ef0cfcSnicm SP_PARM->_mouse_mask2 = result;
1956*c7ef0cfcSnicm
1957*c7ef0cfcSnicm /*
1958*c7ef0cfcSnicm * Make a mask corresponding to the states we will need to
1959*c7ef0cfcSnicm * retain (temporarily) while building up the state that the
1960*c7ef0cfcSnicm * user asked for.
1961*c7ef0cfcSnicm */
1962*c7ef0cfcSnicm for (b = 1; b <= MAX_BUTTONS; ++b) {
1963*c7ef0cfcSnicm if (SP_PARM->_mouse_mask2 & MASK_TRIPLE_CLICK(b))
1964*c7ef0cfcSnicm SP_PARM->_mouse_mask2 |= MASK_DOUBLE_CLICK(b);
1965*c7ef0cfcSnicm if (SP_PARM->_mouse_mask2 & MASK_DOUBLE_CLICK(b))
1966*c7ef0cfcSnicm SP_PARM->_mouse_mask2 |= MASK_CLICK(b);
1967*c7ef0cfcSnicm if (SP_PARM->_mouse_mask2 & MASK_CLICK(b))
1968*c7ef0cfcSnicm SP_PARM->_mouse_mask2 |= (MASK_PRESS(b) |
1969*c7ef0cfcSnicm MASK_RELEASE(b));
197092dd1ec0Smillert }
197181d8c4e1Snicm }
197281d8c4e1Snicm }
197392dd1ec0Smillert }
1974*c7ef0cfcSnicm returnMMask(result);
1975*c7ef0cfcSnicm }
1976*c7ef0cfcSnicm
1977*c7ef0cfcSnicm #if NCURSES_SP_FUNCS
1978*c7ef0cfcSnicm NCURSES_EXPORT(mmask_t)
mousemask(mmask_t newmask,mmask_t * oldmask)1979*c7ef0cfcSnicm mousemask(mmask_t newmask, mmask_t * oldmask)
1980*c7ef0cfcSnicm {
1981*c7ef0cfcSnicm return NCURSES_SP_NAME(mousemask) (CURRENT_SCREEN, newmask, oldmask);
1982*c7ef0cfcSnicm }
1983*c7ef0cfcSnicm #endif
198492dd1ec0Smillert
198584af20ceSmillert NCURSES_EXPORT(bool)
wenclose(const WINDOW * win,int y,int x)198623bb66c4Smillert wenclose(const WINDOW *win, int y, int x)
198792dd1ec0Smillert /* check to see if given window encloses given screen location */
198892dd1ec0Smillert {
198981d8c4e1Snicm bool result = FALSE;
199081d8c4e1Snicm
1991*c7ef0cfcSnicm T((T_CALLED("wenclose(%p,%d,%d)"), (const void *) win, y, x));
199281d8c4e1Snicm
199381d8c4e1Snicm if (win != 0) {
199492dd1ec0Smillert y -= win->_yoffset;
199581d8c4e1Snicm result = ((win->_begy <= y &&
199692dd1ec0Smillert win->_begx <= x &&
199792dd1ec0Smillert (win->_begx + win->_maxx) >= x &&
199892dd1ec0Smillert (win->_begy + win->_maxy) >= y) ? TRUE : FALSE);
199992dd1ec0Smillert }
200081d8c4e1Snicm returnBool(result);
200192dd1ec0Smillert }
200292dd1ec0Smillert
200384af20ceSmillert NCURSES_EXPORT(int)
NCURSES_SP_NAME(mouseinterval)2004*c7ef0cfcSnicm NCURSES_SP_NAME(mouseinterval) (NCURSES_SP_DCLx int maxclick)
200592dd1ec0Smillert /* set the maximum mouse interval within which to recognize a click */
200692dd1ec0Smillert {
200792dd1ec0Smillert int oldval;
200892dd1ec0Smillert
2009*c7ef0cfcSnicm T((T_CALLED("mouseinterval(%p,%d)"), (void *) SP_PARM, maxclick));
201081d8c4e1Snicm
2011*c7ef0cfcSnicm if (SP_PARM != 0) {
2012*c7ef0cfcSnicm oldval = SP_PARM->_maxclick;
201392dd1ec0Smillert if (maxclick >= 0)
2014*c7ef0cfcSnicm SP_PARM->_maxclick = maxclick;
201592dd1ec0Smillert } else {
201692dd1ec0Smillert oldval = DEFAULT_MAXCLICK;
201792dd1ec0Smillert }
201892dd1ec0Smillert
201981d8c4e1Snicm returnCode(oldval);
202092dd1ec0Smillert }
202192dd1ec0Smillert
2022*c7ef0cfcSnicm #if NCURSES_SP_FUNCS
2023*c7ef0cfcSnicm NCURSES_EXPORT(int)
mouseinterval(int maxclick)2024*c7ef0cfcSnicm mouseinterval(int maxclick)
2025*c7ef0cfcSnicm {
2026*c7ef0cfcSnicm return NCURSES_SP_NAME(mouseinterval) (CURRENT_SCREEN, maxclick);
2027*c7ef0cfcSnicm }
2028*c7ef0cfcSnicm #endif
2029*c7ef0cfcSnicm
203092dd1ec0Smillert /* This may be used by other routines to ask for the existence of mouse
203192dd1ec0Smillert support */
2032*c7ef0cfcSnicm NCURSES_EXPORT(bool)
_nc_has_mouse(SCREEN * sp)2033*c7ef0cfcSnicm _nc_has_mouse(SCREEN *sp)
203423bb66c4Smillert {
2035*c7ef0cfcSnicm return (((0 == sp) || (sp->_mouse_type == M_NONE)) ? FALSE : TRUE);
203692dd1ec0Smillert }
203792dd1ec0Smillert
203884af20ceSmillert NCURSES_EXPORT(bool)
NCURSES_SP_NAME(has_mouse)2039*c7ef0cfcSnicm NCURSES_SP_NAME(has_mouse) (NCURSES_SP_DCL0)
2040*c7ef0cfcSnicm {
2041*c7ef0cfcSnicm return _nc_has_mouse(SP_PARM);
2042*c7ef0cfcSnicm }
2043*c7ef0cfcSnicm
2044*c7ef0cfcSnicm #if NCURSES_SP_FUNCS
2045*c7ef0cfcSnicm NCURSES_EXPORT(bool)
has_mouse(void)2046*c7ef0cfcSnicm has_mouse(void)
2047*c7ef0cfcSnicm {
2048*c7ef0cfcSnicm return _nc_has_mouse(CURRENT_SCREEN);
2049*c7ef0cfcSnicm }
2050*c7ef0cfcSnicm #endif
2051*c7ef0cfcSnicm
2052*c7ef0cfcSnicm NCURSES_EXPORT(bool)
wmouse_trafo(const WINDOW * win,int * pY,int * pX,bool to_screen)205381d8c4e1Snicm wmouse_trafo(const WINDOW *win, int *pY, int *pX, bool to_screen)
205492dd1ec0Smillert {
205592dd1ec0Smillert bool result = FALSE;
205692dd1ec0Smillert
2057*c7ef0cfcSnicm T((T_CALLED("wmouse_trafo(%p,%p,%p,%d)"),
2058*c7ef0cfcSnicm (const void *) win,
2059*c7ef0cfcSnicm (void *) pY,
2060*c7ef0cfcSnicm (void *) pX,
2061*c7ef0cfcSnicm to_screen));
206281d8c4e1Snicm
206323bb66c4Smillert if (win && pY && pX) {
206423bb66c4Smillert int y = *pY;
206523bb66c4Smillert int x = *pX;
206692dd1ec0Smillert
206723bb66c4Smillert if (to_screen) {
206892dd1ec0Smillert y += win->_begy + win->_yoffset;
206992dd1ec0Smillert x += win->_begx;
207092dd1ec0Smillert if (wenclose(win, y, x))
207192dd1ec0Smillert result = TRUE;
207223bb66c4Smillert } else {
207323bb66c4Smillert if (wenclose(win, y, x)) {
207492dd1ec0Smillert y -= (win->_begy + win->_yoffset);
207592dd1ec0Smillert x -= win->_begx;
207692dd1ec0Smillert result = TRUE;
207792dd1ec0Smillert }
207892dd1ec0Smillert }
207923bb66c4Smillert if (result) {
208092dd1ec0Smillert *pX = x;
208192dd1ec0Smillert *pY = y;
208292dd1ec0Smillert }
208392dd1ec0Smillert }
208481d8c4e1Snicm returnBool(result);
208592dd1ec0Smillert }
2086