?? lib_mouse.c
字號:
* * We accomplish this in two passes. The first pass merges press/release * pairs into click events. The second merges runs of click events into * double or triple-click events. * * It's possible that the run may not resolve to a single event (for * example, if the user quadruple-clicks). If so, leading events * in the run are ignored. * * Note that this routine is independent of the format of the specific * format of the pointing-device's reports. We can use it to parse * gestures on anything that reports press/release events on a per- * button basis, as long as the device-dependent mouse code puts stuff * on the queue in MEVENT format. */ if (runcount == 1) { TR(MY_TRACE, ("_nc_mouse_parse: returning simple mouse event %s at slot %ld", _tracemouse(prev), (long) (prev - events))); return (prev->id >= NORMAL_EVENT) ? ((prev->bstate & eventmask) ? TRUE : FALSE) : FALSE; } /* find the start of the run */ runp = eventp; for (n = runcount; n > 0; n--) { runp = PREV(runp); }#ifdef TRACE if (_nc_tracing & TRACE_IEVENT) { _trace_slot("before mouse press/release merge:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", (long) (runp - events), (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX, runcount); }#endif /* TRACE */ /* first pass; merge press/release pairs */ do { merge = FALSE; for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) { if (ep->x == next->x && ep->y == next->y && (ep->bstate & BUTTON_PRESSED) && (!(ep->bstate & BUTTON1_PRESSED) == !(next->bstate & BUTTON1_RELEASED)) && (!(ep->bstate & BUTTON2_PRESSED) == !(next->bstate & BUTTON2_RELEASED)) && (!(ep->bstate & BUTTON3_PRESSED) == !(next->bstate & BUTTON3_RELEASED)) ) { if ((eventmask & BUTTON1_CLICKED) && (ep->bstate & BUTTON1_PRESSED)) { ep->bstate &= ~BUTTON1_PRESSED; ep->bstate |= BUTTON1_CLICKED; merge = TRUE; } if ((eventmask & BUTTON2_CLICKED) && (ep->bstate & BUTTON2_PRESSED)) { ep->bstate &= ~BUTTON2_PRESSED; ep->bstate |= BUTTON2_CLICKED; merge = TRUE; } if ((eventmask & BUTTON3_CLICKED) && (ep->bstate & BUTTON3_PRESSED)) { ep->bstate &= ~BUTTON3_PRESSED; ep->bstate |= BUTTON3_CLICKED; merge = TRUE; } if (merge) next->id = INVALID_EVENT; } } } while (merge);#ifdef TRACE if (_nc_tracing & TRACE_IEVENT) { _trace_slot("before mouse click merge:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", (long) (runp - events), (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX, runcount); }#endif /* TRACE */ /* * Second pass; merge click runs. At this point, click events are * each followed by one invalid event. We merge click events * forward in the queue. * * NOTE: There is a problem with this design! If the application * allows enough click events to pile up in the circular queue so * they wrap around, it will cheerfully merge the newest forward * into the oldest, creating a bogus doubleclick and confusing * the queue-traversal logic rather badly. Generally this won't * happen, because calling getmouse() marks old events invalid and * ineligible for merges. The true solution to this problem would * be to timestamp each MEVENT and perform the obvious sanity check, * but the timer element would have to have sub-second resolution, * which would get us into portability trouble. */ do { MEVENT *follower; merge = FALSE; for (ep = runp; (next = NEXT(ep)) != eventp; ep = next) if (ep->id != INVALID_EVENT) { if (next->id != INVALID_EVENT) continue; follower = NEXT(next); if (follower->id == INVALID_EVENT) continue; /* merge click events forward */ if ((ep->bstate & BUTTON_CLICKED) && (follower->bstate & BUTTON_CLICKED)) { if ((eventmask & BUTTON1_DOUBLE_CLICKED) && (follower->bstate & BUTTON1_CLICKED)) { follower->bstate &= ~BUTTON1_CLICKED; follower->bstate |= BUTTON1_DOUBLE_CLICKED; merge = TRUE; } if ((eventmask & BUTTON2_DOUBLE_CLICKED) && (follower->bstate & BUTTON2_CLICKED)) { follower->bstate &= ~BUTTON2_CLICKED; follower->bstate |= BUTTON2_DOUBLE_CLICKED; merge = TRUE; } if ((eventmask & BUTTON3_DOUBLE_CLICKED) && (follower->bstate & BUTTON3_CLICKED)) { follower->bstate &= ~BUTTON3_CLICKED; follower->bstate |= BUTTON3_DOUBLE_CLICKED; merge = TRUE; } if (merge) ep->id = INVALID_EVENT; } /* merge double-click events forward */ if ((ep->bstate & (BUTTON1_DOUBLE_CLICKED | BUTTON2_DOUBLE_CLICKED | BUTTON3_DOUBLE_CLICKED)) && (follower->bstate & BUTTON_CLICKED)) { if ((eventmask & BUTTON1_TRIPLE_CLICKED) && (follower->bstate & BUTTON1_CLICKED)) { follower->bstate &= ~BUTTON1_CLICKED; follower->bstate |= BUTTON1_TRIPLE_CLICKED; merge = TRUE; } if ((eventmask & BUTTON2_TRIPLE_CLICKED) && (follower->bstate & BUTTON2_CLICKED)) { follower->bstate &= ~BUTTON2_CLICKED; follower->bstate |= BUTTON2_TRIPLE_CLICKED; merge = TRUE; } if ((eventmask & BUTTON3_TRIPLE_CLICKED) && (follower->bstate & BUTTON3_CLICKED)) { follower->bstate &= ~BUTTON3_CLICKED; follower->bstate |= BUTTON3_TRIPLE_CLICKED; merge = TRUE; } if (merge) ep->id = INVALID_EVENT; } } } while (merge);#ifdef TRACE if (_nc_tracing & TRACE_IEVENT) { _trace_slot("before mouse event queue compaction:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", (long) (runp - events), (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX, runcount); }#endif /* TRACE */ /* * Now try to throw away trailing events flagged invalid, or that * don't match the current event mask. */ for (; runcount; prev = PREV(eventp), runcount--) if (prev->id == INVALID_EVENT || !(prev->bstate & eventmask)) { eventp = prev; }#ifdef TRACE if (_nc_tracing & TRACE_IEVENT) { _trace_slot("after mouse event queue compaction:"); _tracef("_nc_mouse_parse: run starts at %ld, ends at %ld, count %d", (long) (runp - events), (long) ((eventp - events) + (EV_MAX - 1)) % EV_MAX, runcount); } for (ep = runp; ep != eventp; ep = NEXT(ep)) if (ep->id != INVALID_EVENT) TR(MY_TRACE, ("_nc_mouse_parse: returning composite mouse event %s at slot %ld", _tracemouse(ep), (long) (ep - events)));#endif /* TRACE */ /* after all this, do we have a valid event? */ return (PREV(eventp)->id != INVALID_EVENT);}static void_nc_mouse_wrap(SCREEN * sp GCC_UNUSED)/* release mouse -- called by endwin() before shellout/exit */{ TR(MY_TRACE, ("_nc_mouse_wrap() called")); switch (SP->_mouse_type) { case M_XTERM: if (eventmask) mouse_activate(FALSE); break;#if USE_GPM_SUPPORT /* GPM: pass all mouse events to next client */ case M_GPM: break;#endif#if USE_SYSMOUSE case M_SYSMOUSE: mouse_activate(FALSE); break;#endif case M_NONE: break; }}static void_nc_mouse_resume(SCREEN * sp GCC_UNUSED)/* re-connect to mouse -- called by doupdate() after shellout */{ TR(MY_TRACE, ("_nc_mouse_resume() called")); switch (SP->_mouse_type) { case M_XTERM: /* xterm: re-enable reporting */ if (eventmask) mouse_activate(TRUE); break;#if USE_GPM_SUPPORT case M_GPM: /* GPM: reclaim our event set */ break;#endif#if USE_SYSMOUSE case M_SYSMOUSE: mouse_activate(TRUE); break;#endif case M_NONE: break; }}/************************************************************************** * * Mouse interface entry points for the API * **************************************************************************/NCURSES_EXPORT(int)getmouse(MEVENT * aevent)/* grab a copy of the current mouse event */{ T((T_CALLED("getmouse(%p)"), aevent)); if (aevent && (SP->_mouse_type != M_NONE)) { /* compute the current-event pointer */ MEVENT *prev = PREV(eventp); /* copy the event we find there */ *aevent = *prev; TR(TRACE_IEVENT, ("getmouse: returning event %s from slot %ld", _tracemouse(prev), (long) (prev - events))); prev->id = INVALID_EVENT; /* so the queue slot becomes free */ returnCode(OK); } returnCode(ERR);}NCURSES_EXPORT(int)ungetmouse(MEVENT * aevent)/* enqueue a synthesized mouse event to be seen by the next wgetch() */{ T((T_CALLED("ungetmouse(%p)"), aevent)); /* stick the given event in the next-free slot */ *eventp = *aevent; /* bump the next-free pointer into the circular list */ eventp = NEXT(eventp); /* push back the notification event on the keyboard queue */ returnCode(ungetch(KEY_MOUSE));}NCURSES_EXPORT(mmask_t)mousemask(mmask_t newmask, mmask_t * oldmask)/* set the mouse event mask */{ mmask_t result = 0; T((T_CALLED("mousemask(%#lx,%p)"), newmask, oldmask)); if (oldmask) *oldmask = eventmask; if (!newmask && !initialized) returnBits(0); _nc_mouse_init(); if (SP->_mouse_type != M_NONE) { eventmask = newmask & (REPORT_MOUSE_POSITION | BUTTON_ALT | BUTTON_CTRL | BUTTON_SHIFT | BUTTON_PRESSED | BUTTON_RELEASED | BUTTON_CLICKED | BUTTON1_DOUBLE_CLICKED | BUTTON1_TRIPLE_CLICKED | BUTTON2_DOUBLE_CLICKED | BUTTON2_TRIPLE_CLICKED | BUTTON3_DOUBLE_CLICKED | BUTTON3_TRIPLE_CLICKED); mouse_activate(eventmask != 0); result = eventmask; } returnBits(result);}NCURSES_EXPORT(bool)wenclose(const WINDOW *win, int y, int x)/* check to see if given window encloses given screen location */{ bool result = FALSE; T((T_CALLED("wenclose(%p,%d,%d)"), win, y, x)); if (win != 0) { y -= win->_yoffset; result = ((win->_begy <= y && win->_begx <= x && (win->_begx + win->_maxx) >= x && (win->_begy + win->_maxy) >= y) ? TRUE : FALSE); } returnBool(result);}NCURSES_EXPORT(int)mouseinterval(int maxclick)/* set the maximum mouse interval within which to recognize a click */{ int oldval; T((T_CALLED("mouseinterval(%d)"), maxclick)); if (SP != 0) { oldval = SP->_maxclick; if (maxclick >= 0) SP->_maxclick = maxclick; } else { oldval = DEFAULT_MAXCLICK; } returnCode(oldval);}/* This may be used by other routines to ask for the existence of mouse support */NCURSES_EXPORT(int)_nc_has_mouse(void){ return (SP->_mouse_type == M_NONE ? 0 : 1);}NCURSES_EXPORT(bool)wmouse_trafo(const WINDOW *win, int *pY, int *pX, bool to_screen){ bool result = FALSE; T((T_CALLED("wmouse_trafo(%p,%p,%p,%d)"), win, pY, pX, to_screen)); if (win && pY && pX) { int y = *pY; int x = *pX; if (to_screen) { y += win->_begy + win->_yoffset; x += win->_begx; if (wenclose(win, y, x)) result = TRUE; } else { if (wenclose(win, y, x)) { y -= (win->_begy + win->_yoffset); x -= win->_begx; result = TRUE; } } if (result) { *pX = x; *pY = y; } } returnBool(result);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -