#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 #include #include #include #include #include /*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<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); }