On Tue, Sep 09, 2025 at 11:12:48PM +0000, Robin Haberkorn wrote: > Hello, > > here are the mouse-related fixes I was discussing earlier. > See commit messages for more details.
thanks - will review and see where we're disagreeing :-) > Is there a real version control system for ncurses or are you working > will tarballs and patch series only? https://invisible-island.net/personal/git-exports.html > These fixes will probably take many years to become widespread on many > installations. Unfortunately, I did not find workarounds that will fully > solve the issues. You should not reset the mouse mask unless you have to to > any avoid additional bogus BUTTON3_PRESSED events when scrolling > horizontally. > Also, you could ignore BUTTON2_PRESSED and react only to BUTTON2_RELEASED. > You will inevitably loose the separation between PRESSED and RELEASED events > even on terminal emulators that do deliver them separately. > > Best regards, > Robin > > -- > @ii._._.*.._+__.+_+.+...+.+.++..+*+.+._.+...*_*.*.__+__._._.++..+_*.++__+__ > .+_..*...+.+_+__.+._.+...*_+_+__._ ...*_ +.+._.+.._+*+_+__._._ .+_..+.+***_ > . *_+_+__.+.*.++..+_+.*.__+_ _.+...*_*_+__.++*.+...++..+* +.+.._+__._+_.+.. > .++..+*_.*...+*+.+.*_ +*+i2^rj.u#__%uu#_.%uu#_+%uu#_*!+!0a"t1010^t^c^c'0a^# > 1010"=d'0a-100000"=d'0auuqq*100+q[_^euu]uq-rq:^/100@oo,+,+,+oqq^t0uq@o*+*!! > From 7a335729a68f24192be14c73f1b00f3bc69702df Mon Sep 17 00:00:00 2001 > From: Robin Haberkorn <[email protected]> > Date: Wed, 10 Sep 2025 00:25:17 +0300 > Subject: [PATCH 1/2] fixed horizontal mouse scroll events > > These can be delivered by Xterm and GNOME Terminal > in SGR mouse mode. > They were erroneously reported as BUTTON3_PRESSED. > --- > ncurses/base/lib_mouse.c | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/ncurses/base/lib_mouse.c b/ncurses/base/lib_mouse.c > index 65cb005f..06748890 100644 > --- a/ncurses/base/lib_mouse.c > +++ b/ncurses/base/lib_mouse.c > @@ -984,7 +984,12 @@ handle_wheel(SCREEN *sp, MEVENT * eventp, int button, > int wheel) > } > break; > case 2: > - PRESS_POSITION(3); > + if (wheel) { > + /* Ignore this event as it is not a true press of the button */ > + eventp->bstate = REPORT_MOUSE_POSITION; > + } else { > + PRESS_POSITION(3); > + } > break; > default: > /* > -- > 2.50.1 > > From 315c4b332bee8535077a9dfca8e7d5d5ba547ec4 Mon Sep 17 00:00:00 2001 > From: Robin Haberkorn <[email protected]> > Date: Wed, 10 Sep 2025 01:36:36 +0300 > Subject: [PATCH 2/2] fixed processing of multiple simultaneous mouse events, > ie. middle clicks in certain terminal emulators > > * At least on Xterm and simpleterm (st) pressing the middle mouse button > sends a PRESSED and RELEASED event immediately when releasing the button. > These will have to be read with two getmouse() calls. > This is a rare case where the _mouse_events queue is actually made use of. > * Unfortunately, the queue was rather a stack. We need separate > read and write pointers for a proper circular queue. > The order of events returned by getmouse() was therefore reversed. > * Also, if you mask for CLICKED events, but disabled click detection > via mouseinterval(0), _nc_mouse_parse() would kick in and synthesize CLICKED > events when the queue actually has more than 1 entry as happens when > pressing > the middle button. > This had to be guarded against explicitly. > --- > ncurses/base/lib_mouse.c | 53 +++++++++++++++++++++------------------- > ncurses/curses.priv.h | 3 ++- > 2 files changed, 30 insertions(+), 26 deletions(-) > > diff --git a/ncurses/base/lib_mouse.c b/ncurses/base/lib_mouse.c > index 06748890..8e9cce74 100644 > --- a/ncurses/base/lib_mouse.c > +++ b/ncurses/base/lib_mouse.c > @@ -786,7 +786,7 @@ _nc_mouse_init(SCREEN *sp) > > TR(MY_TRACE, ("set _mouse_initialized")); > > - sp->_mouse_eventp = FirstEV(sp); > + sp->_mouse_readp = sp->_mouse_writep = FirstEV(sp); > for (i = 0; i < EV_MAX; i++) > Invalidate(sp->_mouse_events + i); > > @@ -806,7 +806,7 @@ _nc_mouse_init(SCREEN *sp) > static bool > _nc_mouse_event(SCREEN *sp) > { > - MEVENT *eventp = sp->_mouse_eventp; > + MEVENT *eventp = sp->_mouse_writep; > bool result = FALSE; > > (void) eventp; > @@ -874,7 +874,7 @@ _nc_mouse_event(SCREEN *sp) > eventp->z = 0; > > /* bump the next-free pointer into the circular list */ > - sp->_mouse_eventp = NEXT(eventp); > + sp->_mouse_writep = NEXT(eventp); > result = TRUE; > break; > } > @@ -899,7 +899,7 @@ _nc_mouse_event(SCREEN *sp) > } > > /* bump the next-free pointer into the circular list */ > - sp->_mouse_eventp = eventp = NEXT(eventp); > + sp->_mouse_writep = eventp = NEXT(eventp); > result = TRUE; > } > break; > @@ -921,7 +921,7 @@ _nc_mouse_event(SCREEN *sp) > } > > /* bump the next-free pointer into the circular list */ > - sp->_mouse_eventp = eventp = NEXT(eventp); > + sp->_mouse_writep = eventp = NEXT(eventp); > result = TRUE; > } > break; > @@ -1360,7 +1360,7 @@ _nc_mouse_inline(SCREEN *sp) > /* mouse report received in the keyboard stream -- parse its info */ > { > bool result = FALSE; > - MEVENT *eventp = sp->_mouse_eventp; > + MEVENT *eventp = sp->_mouse_writep; > > TR(MY_TRACE, ("_nc_mouse_inline() called")); > > @@ -1385,7 +1385,7 @@ _nc_mouse_inline(SCREEN *sp) > (long) IndexEV(sp, eventp))); > > /* bump the next-free pointer into the circular list */ > - sp->_mouse_eventp = NEXT(eventp); > + sp->_mouse_writep = NEXT(eventp); > > if (!result) { > /* If this event is from a wheel-mouse, treat it like position > @@ -1506,7 +1506,7 @@ static bool > _nc_mouse_parse(SCREEN *sp, int runcount) > /* parse a run of atomic mouse events into a gesture */ > { > - MEVENT *eventp = sp->_mouse_eventp; > + MEVENT *eventp = sp->_mouse_writep; > MEVENT *next, *ep; > MEVENT *first_valid = NULL; > MEVENT *first_invalid = NULL; > @@ -1517,6 +1517,10 @@ _nc_mouse_parse(SCREEN *sp, int runcount) > > TR(MY_TRACE, ("_nc_mouse_parse(%d) called", runcount)); > > + if (!sp->_maxclick) > + return sp->_mouse_readp && ValidEvent(sp->_mouse_readp) && > + ((sp->_mouse_readp->bstate & sp->_mouse_mask) != 0); > + > /* > * When we enter this routine, the event list next-free pointer > * points just past a run of mouse events that we know were separated > @@ -1552,6 +1556,7 @@ _nc_mouse_parse(SCREEN *sp, int runcount) > Invalidate(ep); > ep = NEXT(ep); > } > + assert(ep == sp->_mouse_readp); > > #ifdef TRACE > if (USE_TRACEF(TRACE_IEVENT)) { > @@ -1728,7 +1733,7 @@ _nc_mouse_parse(SCREEN *sp, int runcount) > if (first_invalid == NULL) { > first_invalid = eventp; > } > - sp->_mouse_eventp = first_invalid; > + sp->_mouse_writep = first_invalid; > > #ifdef TRACE > if (first_valid != NULL) { > @@ -1835,36 +1840,34 @@ NCURSES_EXPORT(int) > NCURSES_SP_NAME(getmouse) (NCURSES_SP_DCLx MEVENT * aevent) > { > int result = ERR; > - MEVENT *eventp; > + MEVENT *readp; > > T((T_CALLED("getmouse(%p,%p)"), (void *) SP_PARM, (void *) aevent)); > > if ((aevent != NULL) && > (SP_PARM != NULL) && > (SP_PARM->_mouse_type != M_NONE) && > - (eventp = SP_PARM->_mouse_eventp) != NULL) { > - /* compute the current-event pointer */ > - MEVENT *prev = PREV(eventp); > - > + (readp = SP_PARM->_mouse_readp) != NULL) { > /* > * Discard events not matching mask (there could be still some if > * _nc_mouse_parse was not called, e.g., when _nc_mouse_inline returns > * false). > */ > - while (ValidEvent(prev) && (!(prev->bstate & SP_PARM->_mouse_mask2))) { > - Invalidate(prev); > - prev = PREV(prev); > + while (readp != SP_PARM->_mouse_writep && > + (!ValidEvent(readp) || !(readp->bstate & > SP_PARM->_mouse_mask2))) { > + Invalidate(readp); > + readp = NEXT(readp); > } > - if (ValidEvent(prev)) { > + if (readp != SP_PARM->_mouse_writep && ValidEvent(readp)) { > /* copy the event we find there */ > - *aevent = *prev; > + *aevent = *readp; > > TR(TRACE_IEVENT, ("getmouse: returning event %s from slot %ld", > - _nc_tracemouse(SP_PARM, prev), > - (long) IndexEV(SP_PARM, prev))); > + _nc_tracemouse(SP_PARM, readp), > + (long) IndexEV(SP_PARM, readp))); > > - Invalidate(prev); /* so the queue slot becomes free */ > - SP_PARM->_mouse_eventp = prev; > + Invalidate(readp); /* so the queue slot becomes free */ > + SP_PARM->_mouse_readp = NEXT(readp); > result = OK; > } else { > /* Reset the provided event */ > @@ -1897,13 +1900,13 @@ NCURSES_SP_NAME(ungetmouse) (NCURSES_SP_DCLx MEVENT * > aevent) > > if (aevent != NULL && > SP_PARM != NULL && > - (eventp = SP_PARM->_mouse_eventp) != NULL) { > + (eventp = SP_PARM->_mouse_writep) != NULL) { > > /* stick the given event in the next-free slot */ > *eventp = *aevent; > > /* bump the next-free pointer into the circular list */ > - SP_PARM->_mouse_eventp = NEXT(eventp); > + SP_PARM->_mouse_writep = NEXT(eventp); > > /* push back the notification event on the keyboard queue */ > result = NCURSES_SP_NAME(ungetch) (NCURSES_SP_ARGx KEY_MOUSE); > diff --git a/ncurses/curses.priv.h b/ncurses/curses.priv.h > index 4fed9b97..9536cc51 100644 > --- a/ncurses/curses.priv.h > +++ b/ncurses/curses.priv.h > @@ -1152,7 +1152,8 @@ typedef struct screen { > MouseFormat _mouse_format; /* type of xterm mouse protocol */ > NCURSES_CONST char *_mouse_xtermcap; /* string to enable/disable mouse > */ > MEVENT _mouse_events[EV_MAX]; /* hold the last mouse event > seen */ > - MEVENT *_mouse_eventp; /* next free slot in event queue */ > + MEVENT *_mouse_readp; /* read pointer into event queue */ > + MEVENT *_mouse_writep; /* write pointer into event queue */ > > /* > * These are data that support the proper handling of the panel stack > on an > -- > 2.50.1 > -- Thomas E. Dickey <[email protected]> https://invisible-island.net
signature.asc
Description: PGP signature
