home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
dirs
/
dmouse_407.lzh
/
DMouse
/
dmouse-handler.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-11-18
|
16KB
|
636 lines
#define DEBUG
/*
* DMOUSE-HANDLER.C
*
* (c)Copyright 1989 by Matthew Dillon, All Rights Reserved
*
* V1.20, last revision 3 August 1989
*
* Note on upping the handler process priority. This is done to cause the
* handler task to get CPU before the current input event completes its
* processing so intuition calls made by the process are executed before
* the event is propogated. If said intuition calls block, it's ok
* because they are not blocking the input handler process.
*/
#include "dmouse.h"
#include <hardware/custom.h>
#include <hardware/dmabits.h>
#include <graphics/gfxmacros.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*typedef struct Layer LAYER;*/
typedef IE *IEP;
typedef struct IORequest IORequest;
__far extern struct Custom custom;
DMS *Dms = NULL;
IBASE *IntuitionBase = NULL;
GFXBASE *GfxBase = NULL;
struct LayersBase *LayersBase = NULL;
/*
struct ExecBase *SysBase = NULL;
*/
struct DosLibrary *DOSBase = NULL;
static PORT *IOPort = NULL; /* For IPC messages */
static LIST BlankList; /* list of external blanker programs */
static char STimedout = 0;
static char MTimedout = 0;
static long STime = 0, MTime = 0;
#ifdef DEBUG
static long DBFh = NULL;
#endif
static void *ReqCache = NULL; /* to prevent massive AllocMem()s */
NS Ns = { 0, 0, 64, -1, 1, -1, -1, 0, CUSTOMSCREEN|SCREENQUIET };
IE DummyIE = { 0 };
short NRMe = 0; /* Don't Repeat Mouse Events */
IE *handler();
int doipcmsg(short);
void sendrequest(long, IE *);
void DeleteBlanker(IORequest *);
LAYER *WhichMouseLayer(void);
LAYER *WhichMouseLayer(void);
void
_main()
{
DMS *dms;
IOR *ior;
INT addhand;
IBASE *ib;
/*
SysBase = *(struct ExecBase **)4;
*/
DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0);
{
PROC *proc = (PROC *)FindTask(NULL);
proc->pr_ConsoleTask = NULL;
}
NRMe = 0;
dms = Dms = (DMS *)FindPort(PORTNAME);
if (!dms)
return;
dms->Port.mp_Flags = PA_SIGNAL;
dms->Port.mp_SigBit = AllocSignal(-1);
dms->Port.mp_SigTask = FindTask(NULL);
dms->HandTask = dms->Port.mp_SigTask;
ior = CreateStdIO(&dms->Port);
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0);
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0);
LayersBase = (struct LayersBase *)OpenLibrary("layers.library", 0);
IOPort = CreatePort("DMouse.ipc", 0);
NewList(&BlankList);
if (!IntuitionBase || !GfxBase || !LayersBase)
goto startupfail;
ib = IntuitionBase;
clrmem(&addhand, sizeof(addhand));
addhand.is_Node.ln_Name = "DMouse";
addhand.is_Node.ln_Pri = dms->IPri;
addhand.is_Code = (FPTR)handler;
addhand.is_Data = NULL;
if (OpenDevice("input.device", 0, ior, 0)) {
goto startupfail;
} else {
SCR *scr = NULL;
short sproff = 0;
long ipc_mask;
Signal(dms->ShakeTask, 1 << dms->ShakeSig);
ior->io_Command = IND_ADDHANDLER;
ior->io_Data = (APTR)&addhand;
ior->io_Message.mn_Node.ln_Type = NT_MESSAGE;
DoIO(ior);
ipc_mask = 1 << IOPort->mp_SigBit;
for (;;) {
long sigs = Wait(SBF_C|(1<<dms->Port.mp_SigBit)|ipc_mask);
if (sigs & (1 << dms->Port.mp_SigBit)) {
REQ *msg;
while (msg = (REQ *)GetMsg(&dms->Port)) {
switch((long)msg->Msg.mn_Node.ln_Name) {
case REQ_SCREENON:
if (scr)
CloseScreen(scr);
scr = NULL;
doipcmsg(0x82);
break;
case REQ_SCREENOFF:
if (scr)
ScreenToFront(scr);
if (doipcmsg(0x83) == 0 && scr == NULL) {
if (scr = OpenScreen(&Ns))
SetRGB4(&scr->ViewPort, 0, 0, 0, 0);
}
break;
case REQ_MOUSEON:
if (sproff) {
ON_SPRITE;
sproff = 0;
}
doipcmsg(0x80);
break;
case REQ_MOUSEOFF:
/*
* note, sometimes the sprite gets turned on again, so
* we re-off it every mouse-ptr-timeout
*/
if (doipcmsg(0x81) == 0) {
WaitTOF();
OFF_SPRITE;
sproff = 1;
}
break;
case REQ_DOCMD:
{
long fh = (long)Open("nil:", 1006);
Execute(dms->Cmd, NULL, fh);
if (fh)
Close(fh);
}
break;
case REQ_RAWMOUSE:
{
LAYER *layer;
NRMe = 0;
Forbid();
layer = WhichMouseLayer();
if (msg->ie_Code == IECODE_RBUTTON && dms->LMBEnable && (msg->ie_Qualifier & dms->RQual)) {
WIN *win;
if (layer && (win = (WIN *)layer->Window) && !(win->Flags & BACKDROP) && (win->NextWindow || win->WScreen->FirstWindow != win)) {
if (dms->FBEnable || (win->Flags & WINDOWDEPTH)) {
if (dms->Workbench)
WindowToBack(win);
else
BehindLayer(0, layer);
}
} else if (ib->FirstScreen)
ScreenToBack(ib->FirstScreen);
}
if (layer && layer->Window) {
if (msg->ie_Code == IECODE_LBUTTON && !(((WIN *)layer->Window)->Flags & BACKDROP) && dms->LMBEnable && layer->ClipRect && layer->ClipRect->Next) {
/*
* Note: Case where it is the 'first' click in a series, where dms->CTime is
* garbage, works properly no matter what DoubleClick returns.
*/
if (dms->LQual == 0 || (msg->ie_Qualifier & dms->LQual)) {
if ((APTR)dms->CWin == layer->Window && DoubleClick(dms->CTime.tv_secs, dms->CTime.tv_micro, msg->ie_TimeStamp.tv_secs, msg->ie_TimeStamp.tv_micro))
--dms->CLeft;
else
dms->CLeft = dms->Clicks - 1;
dms->CTime = msg->ie_TimeStamp;
dms->CWin = (WIN *)layer->Window;
if (dms->CLeft == 0) {
dms->CLeft = dms->Clicks;
if (dms->FBEnable || (((WIN *)layer->Window)->Flags & WINDOWDEPTH)) {
if (dms->Workbench)
WindowToFront((WIN *)layer->Window);
else
UpfrontLayer(0, layer);
}
}
}
}
if ((dms->AAEnable & 1) && (void *)layer->Window != (void *)ib->ActiveWindow && msg->ie_Code == IECODE_NOBUTTON && !(msg->ie_Qualifier & 0x7000)) {
if (!ib->ActiveWindow || !ib->ActiveWindow->FirstRequest)
ActivateWindow((WIN *)layer->Window);
}
}
Permit();
}
break;
case REQ_RAWKEY:
{
LAYER *layer;
Forbid();
layer = WhichMouseLayer();
if (layer && layer->Window && (void *)layer->Window != (void *)ib->ActiveWindow) {
if (!ib->ActiveWindow || !ib->ActiveWindow->FirstRequest)
ActivateWindow((WIN *)layer->Window);
}
Permit();
}
break;
#ifdef DEBUG
case REQ_DEBUG:
{
char buf[128];
if (!DBFh) {
DBFh = Open("con:0/0/400/100/dmouse-debug", 1006);
if (!DBFh)
break;
}
sprintf(buf, "%02lx %04lx %04lx (%d,%d)\n",
msg->ie_Class,
msg->ie_Code,
msg->ie_Qualifier,
msg->rq_X,
msg->rq_Y
);
Write(DBFh, buf, strlen(buf));
}
break;
case REQ_DEBUGOFF:
if (DBFh) {
Close(DBFh);
DBFh = NULL;
}
break;
#endif
}
if (ReqCache == NULL && msg->Msg.mn_Length == sizeof(REQ))
ReqCache = (void *)msg;
else
FreeMem(msg, msg->Msg.mn_Length);
}
}
if (sigs & SBF_C)
break;
/*
* IPC request.
*/
if (sigs & ipc_mask) {
IORequest *ior;
while (ior = (IORequest *)GetMsg(IOPort)) {
long req = 0;
if (ior->io_Message.mn_Node.ln_Type == NT_REPLYMSG) {
FreeMem(ior, ior->io_Message.mn_Length);
continue;
}
ior->io_Error = 0;
switch(ior->io_Command) {
case 0x80: /* mouse on */
req = REQ_MOUSEON;
break;
case 0x81: /* mouse off */
req = REQ_MOUSEOFF;
MTimedout = 1;
break;
case 0x82: /* screen on */
req = REQ_SCREENON;
break;
case 0x83: /* screen off*/
req = REQ_SCREENOFF;
STimedout = 1;
break;
case 0x84: /* add hand */
AddHead(&BlankList, ior);
ior = NULL;
break;
case 0x85: /* rem hand */
DeleteBlanker(ior);
ior = NULL;
break;
}
if (req)
sendrequest(req, NULL);
if (ior)
ReplyMsg(&ior->io_Message);
}
}
}
#ifdef DEBUG
if (DBFh) {
Close(DBFh);
DBFh = NULL;
}
#endif
ior->io_Command = IND_REMHANDLER;
ior->io_Data = (APTR)&addhand;
ior->io_Message.mn_Node.ln_Type = NT_MESSAGE;
DoIO(ior);
ior->io_Command = IND_WRITEEVENT; /* NULL EVENT */
ior->io_Length = sizeof(IE);
ior->io_Data = (APTR)&DummyIE;
ior->io_Message.mn_Node.ln_Type = NT_MESSAGE;
DoIO(ior);
CloseDevice(ior);
{
MSG *msg;
while (msg = GetMsg(&dms->Port))
FreeMem(msg, msg->mn_Length);
}
if (scr)
CloseScreen(scr);
if (sproff) {
ON_SPRITE;
sproff = 0;
}
}
goto closedown;
startupfail:
dms->StartupError = 1;
Signal(dms->ShakeTask, 1 << dms->ShakeSig);
Wait(SBF_C);
closedown:
DeleteStdIO(ior);
fail:
if (IOPort) {
IORequest *ior; /* wait for RemReq messages */
doipcmsg(0x86); /* send closedown requests */
Forbid();
while (GetHead(&BlankList)) {
WaitPort(IOPort);
while (ior = (IORequest *)GetMsg(IOPort)) {
if (ior->io_Message.mn_Node.ln_Type == NT_REPLYMSG) {
FreeMem(ior, ior->io_Message.mn_Length);
continue;
}
if (ior->io_Command == 0x85) /* receive remove req */
DeleteBlanker(ior);
else
ReplyMsg(&ior->io_Message); /* ignore other reqs */
}
}
DeletePort(IOPort);
Permit();
}
if (IntuitionBase)
CloseLibrary((LIB *)IntuitionBase);
if (GfxBase)
CloseLibrary((LIB *)GfxBase);
if (LayersBase)
CloseLibrary((LIB *)LayersBase);
CloseLibrary((LIB *)DOSBase);
if (ReqCache)
FreeMem(ReqCache, sizeof(REQ));
Forbid();
Signal(dms->ShakeTask, 1 << dms->ShakeSig);
}
void
DeleteBlanker(ior)
IORequest *ior;
{
IORequest *io2;
ior->io_Error = 0;
for (io2 = (IORequest *)GetHead(&BlankList); io2; io2 = (IORequest *)GetSucc(io2)) {
if (io2->io_Unit == ior->io_Unit) {
Remove(io2);
if (ior)
ReplyMsg(&ior->io_Message);
ReplyMsg(&io2->io_Message);
ior = NULL;
}
}
if (ior) {
ior->io_Error = -1;
ReplyMsg(&ior->io_Message);
}
}
doipcmsg(cmd)
short cmd;
{
short count = 0;
short flags = 1 << (cmd & 0x7F); /* enable flags */
IORequest *iob, *io;
for (iob = (IORequest *)GetHead(&BlankList); iob; iob = (IORequest *)GetSucc(iob)) {
if (cmd == 0x86 || (iob->io_Flags & flags)) {
io = AllocMem(sizeof(IORequest), MEMF_PUBLIC|MEMF_CLEAR);
if (io) {
io->io_Command = cmd;
io->io_Unit = iob->io_Unit;
io->io_Message.mn_ReplyPort = IOPort;
io->io_Message.mn_Length = sizeof(IORequest);
PutMsg(iob->io_Message.mn_ReplyPort, &io->io_Message);
++count;
}
}
}
return((int)count);
}
/*
* The INPUT.DEVICE HANDLER
*/
__geta4 IE *
CHandler(Ev)
IE *Ev;
{
IE *ev;
DMS *dms;
dms = Dms;
for (ev = Ev; ev; ev = ev->ie_NextEvent) { /* chgd feb 1990 3/Ev->ev */
#ifdef DEBUG
if (dms->Debug) {
if (ev->ie_Class != IECLASS_TIMER)
sendrequest(REQ_DEBUG, ev);
} else if (DBFh) {
sendrequest(REQ_DEBUGOFF, ev);
}
#endif
switch(ev->ie_Class) {
case IECLASS_RAWMOUSE:
/*
* Mouse events restore both the screen and mouse pointer.
*/
STime = ev->ie_TimeStamp.tv_secs + dms->STo;
MTime = ev->ie_TimeStamp.tv_secs + dms->MTo;
if (STimedout)
sendrequest(REQ_SCREENON, ev);
if (MTimedout)
sendrequest(REQ_MOUSEON, ev);
STimedout = MTimedout = 0;
/*
* Mouse Acceleration
*/
{
short n;
short s;
if (dms->Acc != 1) {
n = ev->ie_X;
s = 1;
if (n < 0) {
n = -n;
s = -1;
}
if (n > dms->AThresh)
ev->ie_X = s * (short)((n - dms->AThresh - 1) * dms->Acc + dms->AThresh + 1);
n = ev->ie_Y;
s = 1;
if (n < 0) {
n = -n;
s = -1;
}
if (n > dms->AThresh)
ev->ie_Y = s * (short)((n - dms->AThresh - 1) * dms->Acc + dms->AThresh + 1);
}
}
/*
* Auto Activate and LMB (win/scrn front/bak)
*/
if (dms->LMBEnable && ev->ie_Code == IECODE_RBUTTON && (ev->ie_Qualifier & dms->RQual))
ev->ie_Class = IECLASS_NULL; /* remove event */
if (NRMe == 0 && ((dms->AAEnable & 1) || dms->LMBEnable)) {
short old;
NRMe = 1;
if (ev->ie_Code != IECODE_NOBUTTON)
old = SetTaskPri(dms->Port.mp_SigTask, 21);
sendrequest(REQ_RAWMOUSE, ev);
if (ev->ie_Code != IECODE_NOBUTTON) {
SetTaskPri(dms->Port.mp_SigTask, old);
WaitTOF(); /* cause a delay */
}
}
break;
case IECLASS_RAWKEY:
/*
* Keyboard events will kill the screen timeout but not
* the mouse timeout. Note that the priority of the
* co-process must be upped to ensure it is able to make the
* window active before the keystroke is passed further.
*
* key releases are ignored
*
* note: ie_Qualifier may or may not have bit 15 set
*/
if (ev->ie_Code & 0x80)
break;
if (dms->AAEnable & 2) {
short old;
old = SetTaskPri(dms->Port.mp_SigTask, 21);
sendrequest(REQ_RAWKEY, ev);
SetTaskPri(dms->Port.mp_SigTask, old);
WaitTOF(); /* cause a delay */
}
STime = ev->ie_TimeStamp.tv_secs + dms->STo;
if (STimedout) {
sendrequest(REQ_SCREENON, ev);
if (dms->MTo == 0)
sendrequest(REQ_MOUSEON, ev);
}
STimedout = 0;
if (ev->ie_Code == dms->Code && (ev->ie_Qualifier | 0x8000) == dms->Qual) {
sendrequest(REQ_DOCMD, ev);
ev->ie_Class = IECLASS_NULL; /* remove event */
}
break;
case IECLASS_TIMER:
/*
* On a timer event, if timeout has occured execute the operation
* and reset the timeout. Note that this will cause continuous
* timeouts every STo and MTo seconds... required because at any
* time Intuition might turn the mouse back on or open a screen or
* something and I want the blanker's to work in the long run.
*/
{
long old;
if (dms->Reset) {
dms->Reset = 0;
STime = ev->ie_TimeStamp.tv_secs + dms->STo;
MTime = ev->ie_TimeStamp.tv_secs + dms->MTo;
}
if (dms->STo && (old = STime - ev->ie_TimeStamp.tv_secs) < 0) {
STime = ev->ie_TimeStamp.tv_secs + dms->STo + 10;
STimedout = 1;
MTimedout = 1;
if (old > -10) {
sendrequest(REQ_SCREENOFF, ev);
sendrequest(REQ_MOUSEOFF, ev);
}
}
if (dms->MTo && (old = MTime - ev->ie_TimeStamp.tv_secs) < 0) {
MTime = ev->ie_TimeStamp.tv_secs + dms->MTo + 1;
MTimedout = 1;
if (old > -10)
sendrequest(REQ_MOUSEOFF, ev);
}
}
break;
}
}
return(Ev);
}
void
sendrequest(creq, ev)
long creq;
IE *ev;
{
REQ *req;
if (req = ReqCache)
ReqCache = NULL;
else
req = AllocMem(sizeof(REQ), MEMF_PUBLIC);
if (req) {
req->Msg.mn_Node.ln_Name = (char *)creq;
req->Msg.mn_ReplyPort = NULL;
req->Msg.mn_Length = sizeof(REQ);
if (ev) {
req->ie_Class= ev->ie_Class;
req->ie_Code = ev->ie_Code;
req->ie_Qualifier = ev->ie_Qualifier;
req->ie_TimeStamp = ev->ie_TimeStamp;
req->rq_X = ev->ie_X;
req->rq_Y = ev->ie_Y;
}
PutMsg(&Dms->Port, (MSG *)req);
}
}
LAYER *
WhichMouseLayer()
{
IBASE *ib = IntuitionBase;
LAYER *layer = NULL;
SCR *scr = ib->FirstScreen;
for (scr = ib->FirstScreen; scr; scr = scr->NextScreen) {
short mousey = ib->MouseY;
short mousex = ib->MouseX;
if (!(scr->ViewPort.Modes & LACE))
mousey >>= 1;
if (!(scr->ViewPort.Modes & HIRES))
mousex >>= 1;
if (layer = WhichLayer(&scr->LayerInfo, mousex, mousey - scr->ViewPort.DyOffset))
break;
if (mousey >= scr->ViewPort.DyOffset)
break;
}
return(layer);
}