home *** CD-ROM | disk | FTP | other *** search
-
- #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);
- }
-
-
-