home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
disks
/
disk445.lzh
/
OptMouse
/
OptMouse.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-24
|
8KB
|
345 lines
/*
* OptMouse.c
*
* Serial Port Optical Mouse Driver
*
* (c) Copyright 1989 J. Edward Hanway
* This code may be freely redistributed for non-commercial purposes. There
* is NO WARRANTY on this program. The author assumes no responsibility for
* any damages resulting from use of this program. You know the drill.
*
* Language: Lattice C 5.02
*
* Revision History:
*
* Version 1.0 27 May 1989
* Supports Mouse Systems M2/M3 serial optical mouse
* Version 1.1 3 June 1989
* Added support for other device/unit combinations besides serial.device
* (e.g. siosbx.device) *** NOTE: This feature has not been tested. ***
*/
#define VERSION "1.1"
#include <exec/types.h>
#include <devices/serial.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <devices/keyboard.h>
#include <libraries/dos.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>
#include <stdlib.h>
#define SAY(x) \
{if(_Backstdout) {Write(_Backstdout, (x), strlen(x)); Close(_Backstdout);}}
void MemCleanup() {}
/* This stuff is for linking with cback.o (for "load and stay resident" code) */
LONG _stack = 4000; /* stack size */
char *_procname = "OptMouse";/* process name */
LONG _priority = 20; /* priority */
LONG _BackGroundIO = 1; /* requires I/O */
extern BPTR _Backstdout;
static char *ser_portname = "OptMouse";
/* default device/unit */
static char *device = SERIALNAME;
static int unit = 0;
static struct dev {
struct MsgPort *port;
struct IORequest *iob;
BOOL open;
} ser = {NULL, NULL, FALSE},
in = {NULL, NULL, FALSE},
time = {NULL, NULL, FALSE},
key = {NULL, NULL, FALSE};
/* shorthand */
#define SER_IOB ((struct IOExtSer *)(ser.iob))
#define IN_IOB ((struct IOStdReq *)(in.iob))
#define TIME_IOB ((struct timerequest *)(time.iob))
#define KEY_IOB ((struct IOStdReq *)(key.iob))
static signed char b; /* byte read from mouse */
static struct button {
BOOL left, middle, right;
} button, last_button = { FALSE, FALSE, FALSE };
static struct InputEvent event = {
NULL, /* NextEvent */
IECLASS_RAWMOUSE, /* Class */
NULL, /* SubClass */
NULL, /* Code, filled in later */
NULL, /* Qualifier, filled in later */
{ NULL, NULL }, /* Position, filled in later */
{ 0L, 0L } /* TimeStamp */
};
/* Matrix for reading key states. All we care about are the
* shift/ctrl/alt/amiga keys, which are conveniently qrouped in
* keymatrix[12] in the same order as required for the qualifier
*
* The following number, which is the ONLY read length that works for
* KBD_READMATRIX, was documented NOWHERE! I had to find it by trial and error.
*/
#define GODDAMN_KEY_MATRIX_READ_LENGTH 13
static UBYTE keymatrix[16];
void close_dev(struct dev *dev)
{
if(dev->open) {
AbortIO(dev->iob);
CloseDevice(dev->iob);
dev->open = FALSE;
}
if(dev->iob) {
DeleteExtIO(dev->iob);
dev->iob = NULL;
}
if(dev->port) {
DeletePort(dev->port);
dev->port = NULL;
}
}
void die(void)
{
close_dev(&time);
close_dev(&in);
close_dev(&ser);
close_dev(&key);
_exit(0);
}
void open_dev(struct dev *dev, char *portname, char *devname, int unit, int size)
{
if(!(dev->port = CreatePort(portname, 0)) ||
!(dev->iob = CreateExtIO(dev->port, size)) ||
!(dev->open = !OpenDevice(devname, unit, dev->iob, 0L))) {
SAY("Device error\n");
die();
}
}
/* my_DoIO does everything that DoIO does (I hope) except it allows for a break
* signal.
*/
void my_DoIO(struct IORequest *iob)
{
register LONGBITS signals, sigbit;
/* Lattice 5.02 doesn't seem to provide a register-parameter entry to BeginIO,
* so here's a hack that avoids an annoying 3 line assembly language program.
* Just don't try to call BeginIO on anything but iob->io_Device.
*/
#pragma libcall iob->io_Device BeginIO 1e 901
iob->io_Flags |= IOF_QUICK;
BeginIO(iob);
if(!(iob->io_Flags & IOF_QUICK)) {
signals = Wait((sigbit = (1L <<
iob->io_Message.mn_ReplyPort->mp_SigBit)) |
SIGBREAKF_CTRL_C);
if(signals & sigbit)
GetMsg(iob->io_Message.mn_ReplyPort);
if(signals & SIGBREAKF_CTRL_C)
die();
}
}
#undef isspace
int isspace(register char c)
{
return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
}
char *skiparg(register char *s)
{
while(*s && !isspace(*s))
s++;
return s;
}
char *skipwhite(register char *s)
{
while(*s && isspace(*s))
s++;
return s;
}
void _tinymain(char *s)
{
UWORD state = 0;
WORD dx, dy;
BOOL mid_is_shift = 0;
BOOL kill = 0;
/* I'm playing it fast and loose with parsing here */
s = skiparg(s);
s = skipwhite(s);
while(*s == '-') {
switch(*(s+1)) {
case 'k':
case 'K':
kill++;
break;
case 'm':
case 'M':
mid_is_shift++;
break;
}
s = skiparg(s);
s = skipwhite(s);
}
/* device name */
if(*s) {
device = s;
s = skiparg(s);
if(*s) *s++ = '\0';
s = skipwhite(s);
}
/* unit */
if(*s) {
(void) stcd_i(s, &unit);
}
if(FindPort(ser_portname)) {
if(kill) {
Signal(FindTask(_procname),SIGBREAKF_CTRL_C);
SAY("Killed\n");
} else
SAY("Already installed\n");
die();
}
open_dev(&ser, ser_portname, device, unit, sizeof(struct IOExtSer));
open_dev(&in, NULL, "input.device", 0L, sizeof(struct IOStdReq));
open_dev(&time, NULL, TIMERNAME, UNIT_MICROHZ, sizeof(struct timerequest));
open_dev(&key, NULL, "keyboard.device", 0L, sizeof(struct IOStdReq));
SAY("OptMouse " VERSION " \xA9 Copyright 1989 J. Edward Hanway\n");
/* Set serial port parameters:
* 1200 baud, 8 bits, no parity, 1 stop bit, no flow control
*/
SER_IOB->IOSer.io_Command = SDCMD_SETPARAMS;
SER_IOB->io_Baud = 1200;
SER_IOB->io_ReadLen = 8;
SER_IOB->io_StopBits = 1;
SER_IOB->io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE;
my_DoIO(ser.iob);
/* Since each IORequest will be used for only one type of command,
* lots of invariant fields can be filled in here
*/
KEY_IOB->io_Command = KBD_READMATRIX;
KEY_IOB->io_Data = (APTR) keymatrix;
KEY_IOB->io_Length = GODDAMN_KEY_MATRIX_READ_LENGTH;
TIME_IOB->tr_node.io_Command = TR_GETSYSTIME;
IN_IOB->io_Command = IND_WRITEEVENT;
IN_IOB->io_Flags = 0;
IN_IOB->io_Length = sizeof(struct InputEvent);
IN_IOB->io_Data = (APTR) &event;
SER_IOB->IOSer.io_Command = CMD_READ;
SER_IOB->IOSer.io_Length = 1;
SER_IOB->IOSer.io_Data = (APTR) &b;
while(TRUE) {
my_DoIO(ser.iob);
switch(state) {
case 0:
if((b & 0xf8) == 0x80) {
button.right = !(b & (1 << 0));
button.middle = !(b & (1 << 1));
button.left = !(b & (1 << 2));
state++;
}
break;
case 1:
dx = b;
state++;
break;
case 2:
dy = b;
state++;
break;
case 3:
dx += b;
state++;
break;
case 4:
dy += b;
/* Now compose the events to be sent to input.device.
* Currently, 0-4 events (movement, up to 3 button
* state changes) are sent.
/* Valid time stamp is required for double-clicking
* to work properly.
*/
my_DoIO(time.iob);
event.ie_TimeStamp = TIME_IOB->tr_time;
/* Shift key status is needed for shift-click support */
my_DoIO(key.iob);
event.ie_X = dx;
event.ie_Y = -dy;
event.ie_Code = IECODE_NOBUTTON;
event.ie_Qualifier = IEQUALIFIER_RELATIVEMOUSE |
(button.right ? IEQUALIFIER_RBUTTON : 0) |
((button.middle && !mid_is_shift) ? IEQUALIFIER_MIDBUTTON : 0) |
(button.left ? IEQUALIFIER_LEFTBUTTON : 0) |
keymatrix[12] |
((button.middle && mid_is_shift) ?
(IEQUALIFIER_LEFTBUTTON | IEQUALIFIER_LSHIFT) :
0);
if(dx || dy)
my_DoIO(in.iob);
event.ie_X = event.ie_Y = 0;
if(button.left ^ last_button.left) {
event.ie_Code = button.left ? IECODE_LBUTTON :
IECODE_LBUTTON | IECODE_UP_PREFIX;
my_DoIO(in.iob);
}
if(button.middle ^ last_button.middle) {
event.ie_Code = mid_is_shift ?
(button.middle ? IECODE_LBUTTON :
IECODE_LBUTTON | IECODE_UP_PREFIX) :
(button.middle ? IECODE_MBUTTON :
IECODE_MBUTTON | IECODE_UP_PREFIX);
my_DoIO(in.iob);
}
if(button.right ^ last_button.right) {
event.ie_Code = button.right ? IECODE_RBUTTON :
IECODE_RBUTTON | IECODE_UP_PREFIX;
my_DoIO(in.iob);
}
last_button = button;
state = 0;
break;
}
}
}