📄 mou_ser.c
字号:
/* * Copyright (c) 1999, 2000 Greg Haerr <greg@censoft.com> * Portions Copyright (c) 1991 David I. Bell * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. * * UNIX Serial Port Mouse Driver * * This driver opens a serial port directly, and interprets serial data. * Microsoft, PC, Logitech and PS/2 mice are supported. * The PS/2 mouse is supported by using the /dev/psaux device. * * The following environment variables control the mouse type expected * and the serial port to open. * * Environment Var Default Allowed * MOUSE_TYPE pc ms, pc, logi, ps2 * MOUSE_PORT /dev/ttyS1 any serial port or /dev/psaux */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <string.h>#include "device.h"#define TERMIOS 1 /* set to use termios serial port control*/#define SGTTY 0 /* set to use sgtty serial port control*/#define SCALE 3 /* default scaling factor for acceleration */#define THRESH 5 /* default threshhold for acceleration */#if TERMIOS#include <termios.h>#endif#if SGTTY#include <sgtty.h>#endif/* default settings*/#if _MINIX#define MOUSE_PORT "/dev/mouse"#define MOUSE_TYPE "ms"#else#if ELKS#define MOUSE_PORT "/dev/ttys0" /* default mouse tty port */#else#define MOUSE_PORT "/dev/ttyS1" /* default mouse tty port */#endif#define MOUSE_TYPE "pc" /* default mouse type "ms","pc","ps2" */#endif#define MAX_BYTES 128 /* number of bytes for buffer *//* states for the mouse*/#define IDLE 0 /* start of byte sequence */#define XSET 1 /* setting x delta */#define YSET 2 /* setting y delta */#define XADD 3 /* adjusting x delta */#define YADD 4 /* adjusting y delta *//* values in the bytes returned by the mouse for the buttons*/#define PC_LEFT_BUTTON 4#define PC_MIDDLE_BUTTON 2#define PC_RIGHT_BUTTON 1#define MS_LEFT_BUTTON 2#define MS_RIGHT_BUTTON 1#define PS2_CTRL_BYTE 0x08#define PS2_LEFT_BUTTON 1#define PS2_RIGHT_BUTTON 2/* Bit fields in the bytes sent by the mouse.*/#define TOP_FIVE_BITS 0xf8#define BOTTOM_THREE_BITS 0x07#define TOP_BIT 0x80#define SIXTH_BIT 0x40#define BOTTOM_TWO_BITS 0x03#define THIRD_FOURTH_BITS 0x0c#define BOTTOM_SIX_BITS 0x3f/* local data*/static int mouse_fd; /* file descriptor for mouse */static int state; /* IDLE, XSET, ... */static int buttons; /* current mouse buttons pressed*/static int availbuttons; /* which buttons are available */static MWCOORD xd; /* change in x */static MWCOORD yd; /* change in y */static int left; /* because the button values change */static int middle; /* between mice, the buttons are */static int right; /* redefined */static unsigned char *bp; /* buffer pointer */static int nbytes; /* number of bytes left */static unsigned char buffer[MAX_BYTES]; /* data bytes read */static int (*parse)(); /* parse routine *//* local routines*/static int MOU_Open(MOUSEDEVICE *pmd);static void MOU_Close(void);static int MOU_GetButtonInfo(void);static void MOU_GetDefaultAccel(int *pscale,int *pthresh);static int MOU_Read(MWCOORD *dx, MWCOORD *dy, MWCOORD *dz, int *bptr);static int MOU_Poll(void);static int ParsePC(int); /* routine to interpret PC mouse */static int ParseMS(int); /* routine to interpret MS mouse */static int ParsePS2(int); /* routine to interpret PS/2 mouse */MOUSEDEVICE mousedev = { MOU_Open, MOU_Close, MOU_GetButtonInfo, MOU_GetDefaultAccel, MOU_Read,#if _MINIX MOU_Poll#else NULL#endif};/* * Open up the mouse device. * Returns the fd if successful, or negative if unsuccessful. */static intMOU_Open(MOUSEDEVICE *pmd){ char *type; char *port; struct termios termios; /* get mouse type and port*/ if( !(type = getenv("MOUSE_TYPE"))) type = MOUSE_TYPE; if( !(port = getenv("MOUSE_PORT"))) port = MOUSE_PORT; /* set button bits and parse procedure*/ if(!strcmp(type, "pc") || !strcmp(type, "logi")) { /* pc or logitech mouse*/ left = PC_LEFT_BUTTON; middle = PC_MIDDLE_BUTTON; right = PC_RIGHT_BUTTON; parse = ParsePC; } else if (strcmp(type, "ms") == 0) { /* microsoft mouse*/ left = MS_LEFT_BUTTON; right = MS_RIGHT_BUTTON; middle = 0; parse = ParseMS; } else if (strcmp(type, "ps2") == 0) { /* PS/2 mouse*/ left = PS2_LEFT_BUTTON; right = PS2_RIGHT_BUTTON; middle = 0; parse = ParsePS2; } else return -1; /* open mouse port*/ mouse_fd = open(port, O_NONBLOCK); if (mouse_fd < 0) { EPRINTF("Error %d opening serial mouse type %s on port %s.\n", errno, type, port); return -1; }#if SGTTY /* set rawmode serial port using sgtty*/ struct sgttyb sgttyb; if (ioctl(fd, TIOCGETP, &sgttyb) == -1) goto err; sgttyb.sg_flags |= RAW; sgttyb.sg_flags &= ~(EVENP | ODDP | ECHO | XTABS | CRMOD); if (ioctl(fd, TIOCSETP, &sgttyb) == -1) goto err; if (ioctl(fd, TIOCFLUSH, 0) < 0) goto err;#endif#if TERMIOS /* * Note we don't check success for the tcget/setattr calls, * some kernels don't support them for certain devices * (like /dev/psaux). */ /* set rawmode serial port using termios*/ tcgetattr(mouse_fd, &termios); /* These functions appear to be broken in ELKS Dev86 */ if(cfgetispeed(&termios) != B1200) cfsetispeed(&termios, B1200);#if _MINIX if(cfgetospeed(&termios) != B1200) cfsetospeed(&termios, B1200);#endif#if !_MINIX termios.c_cflag &= ~CBAUD; termios.c_cflag |= B1200;#endif termios.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG); termios.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON | BRKINT | IGNBRK); termios.c_cflag &= ~(CSIZE | PARENB); termios.c_cflag |= CS8; termios.c_cc[VMIN] = 0; termios.c_cc[VTIME] = 0; tcsetattr(mouse_fd, TCSAFLUSH, &termios);#endif /* TERMIOS*/ /* initialize data*/ availbuttons = left | middle | right; state = IDLE; nbytes = 0; buttons = 0; xd = 0; yd = 0; return mouse_fd;err: close(mouse_fd); mouse_fd = 0; return -1;}/* * Close the mouse device. */static voidMOU_Close(void){ if (mouse_fd > 0) { close(mouse_fd); } mouse_fd = 0;}/* * Get mouse buttons supported */static intMOU_GetButtonInfo(void){ return availbuttons;}/* * Get default mouse acceleration settings */static voidMOU_GetDefaultAccel(int *pscale,int *pthresh){ *pscale = SCALE; *pthresh = THRESH;}/* * Attempt to read bytes from the mouse and interpret them. * Returns -1 on error, 0 if either no bytes were read or not enough * was read for a complete state, or 1 if the new state was read. * When a new state is read, the current buttons and x and y deltas * are returned. This routine does not block. */static intMOU_Read(MWCOORD *dx, MWCOORD *dy, MWCOORD *dz, int *bptr){ int b; /* * If there are no more bytes left, then read some more, * waiting for them to arrive. On a signal or a non-blocking * error, return saying there is no new state available yet. */ if (nbytes <= 0) { bp = buffer; nbytes = read(mouse_fd, bp, MAX_BYTES); if (nbytes < 0) { if (errno == EINTR || errno == EAGAIN) return 0;#if _MINIX return 0;#else return -1;#endif } } /* * Loop over all the bytes read in the buffer, parsing them. * When a complete state has been read, return the results, * leaving further bytes in the buffer for later calls. */ while (nbytes-- > 0) { if ((*parse)((int) *bp++)) { *dx = xd; *dy = yd; *dz = 0; b = 0; if(buttons & left) b |= MWBUTTON_L; if(buttons & right) b |= MWBUTTON_R; if(buttons & middle) b |= MWBUTTON_M; *bptr = b; return 1; } } return 0;}/* * Input routine for PC mouse. * Returns nonzero when a new mouse state has been completed. */static intParsePC(int byte){ int sign; /* sign of movement */ switch (state) { case IDLE: if ((byte & TOP_FIVE_BITS) == TOP_BIT) { buttons = ~byte & BOTTOM_THREE_BITS; state = XSET; } break; case XSET: sign = 1; if (byte > 127) { byte = 256 - byte; sign = -1; } xd = byte * sign; state = YSET; break; case YSET: sign = 1; if (byte > 127) { byte = 256 - byte; sign = -1; } yd = -byte * sign; state = XADD; break; case XADD: sign = 1; if (byte > 127) { byte = 256 - byte; sign = -1; } xd += byte * sign; state = YADD; break; case YADD: sign = 1; if (byte > 127) { byte = 256 - byte; sign = -1; } yd -= byte * sign; state = IDLE; return 1; } return 0;}/* * Input routine for Microsoft mouse. * Returns nonzero when a new mouse state has been completed. */static intParseMS(int byte){ switch (state) { case IDLE: if (byte & SIXTH_BIT) { buttons = (byte >> 4) & BOTTOM_TWO_BITS; yd = ((byte & THIRD_FOURTH_BITS) << 4); xd = ((byte & BOTTOM_TWO_BITS) << 6); state = XADD; } break; case XADD: xd |= (byte & BOTTOM_SIX_BITS); state = YADD; break; case YADD: yd |= (byte & BOTTOM_SIX_BITS); state = IDLE; if (xd > 127) xd -= 256; if (yd > 127) yd -= 256; return 1; } return 0;}/* * Input routine for PS/2 mouse. * Returns nonzero when a new mouse state has been completed. */static intParsePS2(int byte){ switch (state) { case IDLE: if (byte & PS2_CTRL_BYTE) { buttons = byte & (PS2_LEFT_BUTTON|PS2_RIGHT_BUTTON); state = XSET; } break; case XSET: if(byte > 127) byte -= 256; xd = byte; state = YSET; break; case YSET: if(byte > 127) byte -= 256; yd = -byte; state = IDLE; return 1; } return 0;}static intMOU_Poll(void){ return 1; /* used by _MINIX only*/}/* #define TEST 1 */#if TESTmain(){ MWCOORD x, y, z; int b; DPRINTF("Open Mouse\n"); if( MOU_Open(0) < 0) DPRINTF("open failed mouse\n" ); while(1) { if(MOU_Read(&x, &y, &z, &b) == 1) { DPRINTF("%d,%d,%d\n", x, y, b); } }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -