?? lib_mouse.c
字號(hào):
/**************************************************************************** * Copyright (c) 1998-2002,2003 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, distribute with modifications, sublicense, and/or sell * * copies of the Software, and to permit persons to whom the Software is * * furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * * Except as contained in this notice, the name(s) of the above copyright * * holders shall not be used in advertising or otherwise to promote the * * sale, use or other dealings in this Software without prior written * * authorization. * ****************************************************************************//**************************************************************************** * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * * and: Eric S. Raymond <esr@snark.thyrsus.com> * * and: Thomas E. Dickey 1996-2003 * ****************************************************************************//* * This module is intended to encapsulate ncurses's interface to pointing * devices. * * The first method used is xterm's internal mouse-tracking facility. * The second is Alessandro Rubini's GPM server. * * Notes for implementors of new mouse-interface methods: * * The code is logically split into a lower level that accepts event reports * in a device-dependent format and an upper level that parses mouse gestures * and filters events. The mediating data structure is a circular queue of * MEVENT structures. * * Functionally, the lower level's job is to pick up primitive events and * put them on the circular queue. This can happen in one of two ways: * either (a) _nc_mouse_event() detects a series of incoming mouse reports * and queues them, or (b) code in lib_getch.c detects the kmous prefix in * the keyboard input stream and calls _nc_mouse_inline to queue up a series * of adjacent mouse reports. * * In either case, _nc_mouse_parse() should be called after the series is * accepted to parse the digested mouse reports (low-level MEVENTs) into * a gesture (a high-level or composite MEVENT). * * Don't be too shy about adding new event types or modifiers, if you can find * room for them in the 32-bit mask. The API is written so that users get * feedback on which theoretical event types they won't see when they call * mousemask. There's one bit per button (the RESERVED_EVENT bit) not being * used yet, and a couple of bits open at the high end. */#ifdef __EMX__# include <io.h># define INCL_DOS# define INCL_VIO# define INCL_KBD# define INCL_MOU# define INCL_DOSPROCESS# include <os2.h> /* Need to include before the others */#endif#include <curses.priv.h>MODULE_ID("$Id: lib_mouse.c,v 1.68 2003/11/08 21:50:50 tom Exp $")#include <term.h>#include <tic.h>#if USE_GPM_SUPPORT#ifndef LINT /* don't need this for llib-lncurses */#undef buttons /* term.h defines this, and gpm uses it! */#include <gpm.h>#include <linux/keyboard.h> /* defines KG_* macros */#endif#endif#if USE_SYSMOUSE#undef buttons /* symbol conflict in consio.h */#undef mouse_info /* symbol conflict in consio.h */#include <osreldate.h>#if (__FreeBSD_version >= 400017)#include <sys/consio.h>#include <sys/fbio.h>#else#include <machine/console.h>#endif#endif /* use_SYSMOUSE */#define MY_TRACE TRACE_ICALLS|TRACE_IEVENT#define MASK_RELEASE(x) ((001 << (6 * ((x) - 1))))#define MASK_PRESS(x) ((002 << (6 * ((x) - 1))))#define MASK_CLICK(x) ((004 << (6 * ((x) - 1))))#define MASK_DOUBLE_CLICK(x) ((010 << (6 * ((x) - 1))))#define MASK_TRIPLE_CLICK(x) ((020 << (6 * ((x) - 1))))#define MASK_RESERVED_EVENT(x) ((040 << (6 * ((x) - 1))))#define BUTTON_CLICKED (BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED)#define BUTTON_PRESSED (BUTTON1_PRESSED | BUTTON2_PRESSED | BUTTON3_PRESSED)#define BUTTON_RELEASED (BUTTON1_RELEASED | BUTTON2_RELEASED | BUTTON3_RELEASED)#define INVALID_EVENT -1#define NORMAL_EVENT 0#if USE_GPM_SUPPORT#ifndef LINTstatic Gpm_Connect gpm_connect;#endif#endifstatic mmask_t eventmask; /* current event mask */static bool _nc_mouse_parse(int);static void _nc_mouse_resume(SCREEN *);static void _nc_mouse_wrap(SCREEN *);/* maintain a circular list of mouse events *//* The definition of the circular list size (EV_MAX), is in curses.priv.h, so * wgetch() may refer to the size and call _nc_mouse_parse() before circular * list overflow. */static MEVENT events[EV_MAX]; /* hold the last mouse event seen */static MEVENT *eventp = events; /* next free slot in event queue */#undef NEXT#define NEXT(ep) ((ep == events + EV_MAX - 1) ? events : ep + 1)#undef PREV#define PREV(ep) ((ep == events) ? events + EV_MAX - 1 : ep - 1)#ifdef TRACEstatic void_trace_slot(const char *tag){ MEVENT *ep; _tracef(tag); for (ep = events; ep < events + EV_MAX; ep++) _tracef("mouse event queue slot %ld = %s", (long) (ep - events), _tracemouse(ep));}#endif#if USE_EMX_MOUSE# define TOP_ROW 0# define LEFT_COL 0static int mouse_wfd;static int mouse_thread;static int mouse_activated;static char mouse_buttons[] ={0, 1, 3, 2};# define M_FD(sp) sp->_mouse_fdstatic voidwrite_event(int down, int button, int x, int y){ char buf[6]; unsigned long ignore; strncpy(buf, key_mouse, 3); /* should be "\033[M" */ buf[3] = ' ' + (button - 1) + (down ? 0 : 0x40); buf[4] = ' ' + x - LEFT_COL + 1; buf[5] = ' ' + y - TOP_ROW + 1; DosWrite(mouse_wfd, buf, 6, &ignore);}static voidmouse_server(unsigned long ignored GCC_UNUSED){ unsigned short fWait = MOU_WAIT; /* NOPTRRECT mourt = { 0,0,24,79 }; */ MOUEVENTINFO mouev; HMOU hmou; unsigned short mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN; int nbuttons = 3; int oldstate = 0; char err[80]; unsigned long rc; /* open the handle for the mouse */ if (MouOpen(NULL, &hmou) == 0) { rc = MouSetEventMask(&mask, hmou); if (rc) { /* retry with 2 buttons */ mask = MOUSE_BN1_DOWN | MOUSE_BN2_DOWN; rc = MouSetEventMask(&mask, hmou); nbuttons = 2; } if (rc == 0 && MouDrawPtr(hmou) == 0) { for (;;) { /* sit and wait on the event queue */ rc = MouReadEventQue(&mouev, &fWait, hmou); if (rc) { sprintf(err, "Error reading mouse queue, rc=%lu.\r\n", rc); break; } if (!mouse_activated) goto finish; /* * OS/2 numbers a 3-button mouse inconsistently from other * platforms: * 1 = left * 2 = right * 3 = middle. */ if ((mouev.fs ^ oldstate) & MOUSE_BN1_DOWN) write_event(mouev.fs & MOUSE_BN1_DOWN, mouse_buttons[1], mouev.col, mouev.row); if ((mouev.fs ^ oldstate) & MOUSE_BN2_DOWN) write_event(mouev.fs & MOUSE_BN2_DOWN, mouse_buttons[3], mouev.col, mouev.row); if ((mouev.fs ^ oldstate) & MOUSE_BN3_DOWN) write_event(mouev.fs & MOUSE_BN3_DOWN, mouse_buttons[2], mouev.col, mouev.row); finish: oldstate = mouev.fs; } } else sprintf(err, "Error setting event mask, buttons=%d, rc=%lu.\r\n", nbuttons, rc); DosWrite(2, err, strlen(err), &rc); MouClose(hmou); } DosExit(EXIT_THREAD, 0L);}static voidserver_state(const int state){ /* It would be nice to implement pointer-off and stop looping... */ mouse_activated = state;}#endif /* USE_EMX_MOUSE */#if USE_SYSMOUSEstatic voidhandle_sysmouse(int sig GCC_UNUSED){ struct mouse_info the_mouse; MEVENT *work; the_mouse.operation = MOUSE_GETINFO; if (SP != 0 && SP->_mouse_fd >= 0 && SP->_sysmouse_tail < FIFO_SIZE && ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse) != -1) { if (SP->_sysmouse_head > SP->_sysmouse_tail) { SP->_sysmouse_tail = 0; SP->_sysmouse_head = 0; } work = &(SP->_sysmouse_fifo[SP->_sysmouse_tail]); memset(work, 0, sizeof(*work)); work->id = NORMAL_EVENT; /* there's only one mouse... */ SP->_sysmouse_old_buttons = SP->_sysmouse_new_buttons; SP->_sysmouse_new_buttons = the_mouse.u.data.buttons & 0x7; if (SP->_sysmouse_new_buttons) { if (SP->_sysmouse_new_buttons & 1) work->bstate |= BUTTON1_PRESSED; if (SP->_sysmouse_new_buttons & 2) work->bstate |= BUTTON2_PRESSED; if (SP->_sysmouse_new_buttons & 4) work->bstate |= BUTTON3_PRESSED; } else { if (SP->_sysmouse_old_buttons & 1) work->bstate |= BUTTON1_RELEASED; if (SP->_sysmouse_old_buttons & 2) work->bstate |= BUTTON2_RELEASED; if (SP->_sysmouse_old_buttons & 4) work->bstate |= BUTTON3_RELEASED; } /* for cosmetic bug in syscons.c on FreeBSD 3.[34] */ the_mouse.operation = MOUSE_HIDE; ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse); the_mouse.operation = MOUSE_SHOW; ioctl(SP->_mouse_fd, CONS_MOUSECTL, &the_mouse); /* * We're only interested if the button is pressed or released. * FIXME: implement continuous event-tracking. */ if (SP->_sysmouse_new_buttons != SP->_sysmouse_old_buttons) { SP->_sysmouse_tail += 1; } work->x = the_mouse.u.data.x / SP->_sysmouse_char_width; work->y = the_mouse.u.data.y / SP->_sysmouse_char_height; }}#endifstatic int initialized;static voidinit_xterm_mouse(void){ SP->_mouse_type = M_XTERM; SP->_mouse_xtermcap = tigetstr("XM"); if (!VALID_STRING(SP->_mouse_xtermcap)) SP->_mouse_xtermcap = "\033[?1000%?%p1%{1}%=%th%el%;";}#if !USE_EMX_MOUSEstatic voidenable_xterm_mouse(int enable){ putp(tparm(SP->_mouse_xtermcap, enable));}#endif /* !USE_EMX_MOUSE */static voidinitialize_mousetype(void){ static const char *xterm_kmous = "\033[M"; /* Try gpm first, because gpm may be configured to run in xterm */#if USE_GPM_SUPPORT /* GPM does printf's without checking if stdout is a terminal */ if (isatty(fileno(stdout))) { /* GPM: initialize connection to gpm server */ gpm_connect.eventMask = GPM_DOWN | GPM_UP; gpm_connect.defaultMask = ~(gpm_connect.eventMask | GPM_HARD); gpm_connect.minMod = 0; gpm_connect.maxMod = ~((1 << KG_SHIFT) | (1 << KG_SHIFTL) | (1 << KG_SHIFTR)); if (Gpm_Open(&gpm_connect, 0) >= 0) { /* returns the file-descriptor */ SP->_mouse_type = M_GPM; SP->_mouse_fd = gpm_fd; return; } }#endif /* OS/2 VIO */#if USE_EMX_MOUSE if (!mouse_thread && strstr(cur_term->type.term_names, "xterm") == 0 && key_mouse) { int handles[2]; if (pipe(handles) < 0) { perror("mouse pipe error"); return; } else { int rc; if (!mouse_buttons[0]) { char *s = getenv("MOUSE_BUTTONS_123"); mouse_buttons[0] = 1; if (s && strlen(s) >= 3) { mouse_buttons[1] = s[0] - '0'; mouse_buttons[2] = s[1] - '0'; mouse_buttons[3] = s[2] - '0'; } } mouse_wfd = handles[1]; M_FD(SP) = handles[0]; /* Needed? */ setmode(handles[0], O_BINARY); setmode(handles[1], O_BINARY); /* Do not use CRT functions, we may single-threaded. */ rc = DosCreateThread((unsigned long *) &mouse_thread, mouse_server, 0, 0, 8192); if (rc) { printf("mouse thread error %d=%#x", rc, rc); return; } else { SP->_mouse_type = M_XTERM; return; } } }#endif#if USE_SYSMOUSE { struct mouse_info the_mouse; char *the_device = 0; if (isatty(SP->_ifd)) the_device = ttyname(SP->_ifd); if (the_device == 0) the_device = "/dev/tty"; SP->_mouse_fd = open(the_device, O_RDWR); if (SP->_mouse_fd >= 0) { /* * sysmouse does not have a usable user interface for obtaining * mouse events. The logical way to proceed (reading data on a * stream) only works if one opens the device as root. Even in * that mode, careful examination shows we lose events * occasionally. The interface provided for user programs is to * establish a signal handler. really. *
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -