Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!think.com!yale.edu!ox.com!heifetz!tbomb!time From: time@ice.com (Tim Endres) Newsgroups: comp.sys.mac.programmer Subject: Re: Journaling (record & playback) of inputs Date: Wed, 26 Jun 91 15:33:53 EST Organization: ICE Engineering, Inc. Message-ID: <1CE00001.i2zdal@tbomb.ice.com> Reply-To: time@ice.com X-Mailer: uAccess - Mac Release: 1.5 Lines: 748 In article <1991Jun26.162909.22605@newcastle.ac.uk>, S.W.L.Yip@newcastle.ac.uk (S.W.Yip) writes: > I am stuck, desperate ... please HELP ! > > I am trying to use the "Journaling Mechanism" , Here's some code... BE WARNED IT IS OLD AND PROBABLY BUGGY!!!!!!! tim. # include # include /* for devices.h */ # include /* for THz */ # include /* for DCtlPtr */ # include /* for EventRecord */ # include /* for Rect */ # include /* for monaco */ # include /* for WindowPtr */ # include /* for MenuHandle */ # include /* for GetVolInfo() */ # include /* for GetVolInfo() */ #define DEBUG 1 pascal void DebugStr(aStr) char *aStr; extern 0xABFF; #define P_String 1 #define C_String 0 # define noErr 0 /* in lieu of */ #define jcTickCount 0 #define jcGetMouse 1 #define jcButton 2 #define jcGetKeys 3 #define jcEvent 4 #define jPlayCtl 16 #define jRecordCtl 17 /*extern int JournalFlag : 0x8DE;*/ /*extern int JournalRef : 0x8E8;*/ #define JournalFlag (* (short *) 0x8DE) #define JournalRef (* (short *) 0x8E8) #define jRecordItem 1 #define jOffItem 3 #define jPlayItem 5 # define OWNEDRSRCID(id) (0xC000 | (((-(id)) - 1) << 5)) /* Computes owned resource id */ /* * String constant indexes for STR# resource */ # define EVENTSTR 1 # define DEBUG_RECORD 2 # define DEBUG_ENABLED 3 # define DEBUG_RECORD 4 # define DEBUG_PLAY 5 # define DEBUG_UPDATE 6 # define COUNTSTR 7 # define FILE_NAME 8 # define WRITE_TICK 9 # define WRITE_MOUSE 10 # define WRITE_BUTTON 11 # define WRITE_EVENT 12 # define WRITE_KEYS 13 # define FILE_CLOSE_ERR 14 # define FILE_OPEN_ERR 15 # define FILE_WRITE_ERR 16 # define WHAT_STR 17 # define MESSAGE_STR 18 # define WHERE_STR 19 # define MODIFIERS_STR 20 # define TRUE_STR 21 # define FALSE_STR 22 # define MENU_TITLE 23 # define MENU_STR 24 # define PLAY_DEBUG_STR 25 # define NUMBER_TICK 0 # define NUMBER_MOUSE 1 # define NUMBER_BUTTON 2 # define NUMBER_KEYS 3 # define NUMBER_EVENT 4 /* This structure type holdstthe global variables used by this desk accessory */ typedef struct { short drvrref; /* Driver's reference number */ short rsrcID; /* Computed rsrc id of STR# and WIND resources */ int lastevent; /* Last journaled event number. */ int count; /* Number of events recorded */ char *eventptr; /* Pointer to event storage */ short refnum; /* debug file's refnum. */ short vrefnum; /* debug file's volume refnum */ MenuHandle accmenu; /* The Desk Accessory's menu. */ short menuid; /* The Desk Accessory's menu id. */ char strBuf[256]; /* Buffer to read strings into */ char inline[256]; /* Buffer to read events into */ int index; /* index into inline for getting values */ int playeof; /* indicates eof on input file */ } Globals; static char *text(); pascal short DRVROpen(ctlPB, dCtl) CntrlParam *ctlPB; DCtlPtr dCtl; { GrafPtr savePort; WindowPeek myWindow; long heapGrow; Globals *globals; char *strptr; /* * If the windowPtr is non-nil, we already have a window open. * This desk accessory ignores multiple opens. */ if (dCtl->dCtlWindow != nil) return(noErr); GetPort(&savePort); /* * Get a handle to some storage that will hold our pseudo-global * variables. Save the handle in a location accessible by * all the driver routines. */ dCtl->dCtlStorage = NewHandle(sizeof(Globals)); /* * Compute the resource id of the owned 'STR#' resource that * contains all of the programs text strings. The id is saved * in one place that can be accessed by all the driver routines. */ HLock(dCtl->dCtlStorage); globals = (Globals *) *dCtl->dCtlStorage; globals->rsrcID = OWNEDRSRCID(dCtl->dCtlRefNum); /* * wStorage = nil (allocate on the heap) * visible = false, behind = -1, goAway = true, refCon = 0 */ myWindow = GetNewWindow(globals->rsrcID, nil, (WindowPtr) -1); /* * Set windowKind to the DA refNum, which is negative. */ myWindow->windowKind = dCtl->dCtlRefNum; /* * Store the windowPtr in the Device Control Entry */ dCtl->dCtlWindow = myWindow; SetPort(savePort); dCtl->dCtlMenu = dCtl->dCtlRefNum; strptr = text(MENU_TITLE, globals, C_String); globals->accmenu = NewMenu((short) dCtl->dCtlRefNum, strptr); strptr = text(MENU_STR, globals, C_String); AppendMenu(globals->accmenu, strptr); InsertMenu(globals->accmenu, (short)0); DrawMenuBar(); globals->count = 0; globals->lastevent = 0; globals->drvrref = dCtl->dCtlRefNum; HUnlock(dCtl->dCtlStorage); return(noErr); } pascal short DRVRPrime(ctlPB, dCtl) CntrlParam *ctlPB; DCtlPtr dCtl; { return(noErr); /* Not used in this desk accessory */ } pascal short DRVRStatus(ctlPB, dCtl) CntrlParam *ctlPB; DCtlPtr dCtl; { return(noErr); /* Not used in this desk accessory */ } pascal short DRVRControl(ctlPB, dCtl) CntrlParam *ctlPB; DCtlPtr dCtl; { GrafPtr saveport; Globals *globals; extern void doCtlEvent(), doPeriodic(), drawWindow(); /* * The current grafPort is saved & restored bytthe Desk Manager */ HLock(dCtl->dCtlStorage); /* Lock handle since it will be dereferenced */ globals = (Globals *) *dCtl->dCtlStorage; switch (ctlPB->csCode) { default: break; case 64: /* accEvent */ doCtlEvent(*((EventRecord **) &ctlPB->csParam[0]), globals); break; case 67: /* accMenu */ switch (ctlPB->csParam[1]) { casejjRecordItem: RecordEnable(globals); break; case jPlayItem: PlayEnable(globals); break; case jOffItem: DisAble(globals); SetPort(dCtl->dCtlWindow); drawWindow(dCtl->dCtlWindow, globals); break; } HiliteMenu(0); break; case 65: /* periodicEvent */ /* doPeriodic(dCtl); */ break; case jRecordCtl: /* Recording mode */ #if DEBUG > 3 DebugStr(text(DEBUG_RECORD, globals, P_String)); #endif /* The journalled event is at csParam+4 or csParam[2], since int[] */ globals->lastevent = ctlPB->csParam[2]; globals->eventptr = * ((char **) &ctlPB->csParam[0]); globals->count++; /* if (CmdPeriod()) DisAble(ctlPB, dCtl); */ WriteRecord(globals); /* save event to journal */ /* GetPort(&saveport); */ /* SetPort(dCtl->dCtlWindow); */ /* drawWindow(dCtl->dCtlWindow, globals); */ /* SetPort(saveport); */ break; case jPlayCtl: /* PlayBack mode */ #if DEBUG > 3 DebugStr(text(DEBUG_PLAY, globals, P_String)); #endif globals->eventptr = * ((char **) &ctlPB->csParam[0]); globals->count++; /* if (CmdPeriod()) DisAble(ctlPB, dCtl); */ if (globals->lastevent = ctlPB->csParam[2]) PlayRecord(globals); if (globals->playeof) DisAble(globals); break; } HUnlock(dCtl->dCtlStorage); return(0); } pascal short DRVRClose(ctlPB, dCtl) char *ctlPB; DCtlPtr dCtl; { /* Save & Restore current grafPort? */ WindowPtr window; Globals *globals; HLock(dCtl->dCtlStorage); globals = (Globals *) *dCtl->dCtlStorage; DeleteMenu(dCtl->dCtlMenu); DrawMenuBar(); DisposeMenu(globals->accmenu); HUnlock(dCtl->dCtlStorage); window = (WindowPtr) dCtl->dCtlWindow; if (window != NULL) { dCtl->dCtlWindow = NULL; DisposeWindow(window); } return 0; } PlayRecord(globals) Globals *globas; { #if DEBUG > 3 DebugStr(text(PLAY_DEBUG_STR, globals, P_String)); DebugNum(globals->lastevent); #endif SysBeep(1); switch (globals->lastevent) { case jcTickCount: PlayTick(globals); break; case jcGetMouse: PlayMouse(globals); break; case jcButton: PlayButton(globals); break; case jcGetKeys: PlayKeys(globals); break; case jcEvent: PlayEvent(globals); break; } ReadLine(globals); if (globals->playeof) globals->lastevent = 0; else globals->lastevent = GetNumber(globals); } PlayTick(globals) Globals *globals; { *((long *)globals->eventptr) = GetNumber(globals); } PlayMouse(globals) Globals *globals; { #if DEBUG > 0 DebugPtr(globals->eventptr); #endif ((Point *)globals->eventptr)->h = GetNumber(globals); ((Point *)globals->eventptr)->v = GetNumber(globals); } PlayKeys(globals) Globals *globals; { ((long *)globals->eventptr)[0] = GetNumber(globals); ((long *)globals->eventptr)[1] = GetNumber(globals); ((long *)globals->eventptr)[2] = GetNumber(globals); ((long *)globals->eventptr)[3] = GetNumber(globals); } PlayButton(globals) Globals *globals; { *((Boolean *)globals->eventptr) = (Boolean) GetNumber(globals); } PlayEvent(globals) Globals *globals; { #if DEBUG > 0 DebugPtr(globals->eventptr); #endif ((EventRecord *)globals->eventptr)->what = GetNumber(globals); ((EventRecord *)globals->eventptr)->message = GetNumber(globals); ((EventRecord *)globals->eventptr)->where.h = GetNumber(globals); ((EventRecord *)globals->eventptr)->where.v = GetNumber(globals); ((EventRecord *)globals->eventptr)->modifiers = GetNumber(globals); } GetNumber(globals) Globals *globals; { long mynum; int i; char mystr[50]; for(i=globals->index; globals->inline[i] && (globals->inline[i] != ' ') && (i < 256); i++) mystr[i] = globals->inline[i]; mystr[i++] = 0; StringToNum(mystr, &mynum); globals->index = i; return mynum; } ReadLine(globals) Globals *globals; { long count; short myerr, i, tmp; i = 0; do { count = 1; myerr = FSRead(globals->refnum, &count, &globals->inline[i]); if (globals->inline[i] == 0x0D) { myerr = 0x0D; globals->inline[i] = 0; } else i++; } while (myerr == noErr); if (myerr == eofErr) globals->playeof = true; globals->index = 0; #if DEBUG > 3 tmp = globals->inline[0]; globals->inline[0] = i; DebugStr(globals->inline); globals->inline[0] = tmp; #endif } #define jOffFlag 0 #define jPlayFlag -1 #define jRecordFlag 1 RecordEnable(globals) Globals *globals; { if (JournalFlag != jOffFlag) { SysBeep(60); return; } OpenFile(globals); SetEOF(globals->refnum, (long) 0); JournalRef = globals->drvrref; JournalFlag = jRecordFlag; globals->count = 0; } PlayEnable(globals) Globals *globals; { if (JournalFlag != jOffFlag) { SysBeep(60); return; } globals->playeof = false; OpenFile(globals); ReadLine(globals); /* Prime the inline */ globals->lastevent = GetNumber(globals); #if DEBUG > 3 DebugNum(globals->lastevent); #endif JournalRef = globals->drvrref; JournalFlag = jPlayFlag; globals->count = 0; } DisAble(globals) Globals *globals; { if (JournalFlag == jOffFlag) { SysBeep(60); return; } JournalFlag = jOffFlag; CloseFile(globals); } WriteRecord(globals) Globals *globals; { switch (globals->lastevent) { case jcTickCount: WriteTick(globals); break; case jcGetMouse: WriteMouse(globals); break; case jcButton: WriteButton(globals); break; case jcGetKeys: WriteKeys(globals); break; case jcEvent: WriteEvent(globals); break; } } WriteTick(globals) Globals *globals; { char *title; long count; char mystr[50]; short myerr; NumToString(NUMBER_TICK, mystr); count = strlen(mystr); mystr[count++] = ' '; NumToString(*((long *)globals->eventptr), &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = 0x0D; myerr = FSWrite(globals->refnum, &count, mystr); #if DEBUG > 0 if (myerr != noErr) DebugStr(text(FILE_WRITE_ERR, globals, P_String)); #endif } WriteEvent(globals) Globals *globals; { char *title; long count; char mystr[128]; EventRecord *myevent; short myerr; myevent = (EventRecord *) globals->eventptr; if (myevent->what == nullEvent) return; NumToString(NUMBER_EVENT, mystr); count = strlen(mystr); mystr[count++] = ' '; NumToString(myevent->what, &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = ' '; NumToString(myevent->message, &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = ' '; NumToString(myevent->where.h, &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = ' '; NumToString(myevent->where.v, &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = ' '; mystr[count] = 0; NumToString(myevent->modifiers, &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = 0x0D; myerr = FSWrite(globals->refnum, &count, mystr); #if DEBUG > 0 if (myerr != noErr) DebugStr(text(FILE_WRITE_ERR, globals, P_String)); #endif } WriteMouse(globals) Globals *globals; { char *title; long count; char mystr[128]; Point *mypt; short myerr; NumToString(NUMBER_MOUSE, mystr); count = strlen(mystr); mystr[count++] = ' '; mypt = (Point *) globals->eventptr; NumToString(mypt->h, &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = ' '; NumToString(mypt->v, &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = 0x0D; myerr = FSWrite(globals->refnum, &count, mystr); #if DEBUG > 0 if (myerr != noErr) DebugStr(text(FILE_WRITE_ERR, globals, P_String)); #endif } WriteButton(globals) Globals *globals; { char mystr[128]; long count; Boolean *mybool; short myerr; NumToString(NUMBER_BUTTON, mystr); count = strlen(mystr); mystr[count++] = ' '; mybool = (Boolean *) globals->eventptr; NumToString((int) *mybool, &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = 0x0D; myerr = FSWrite(globals->refnum, &count, mystr); #if DEBUG > 0 if (myerr != noErr) DebugStr(text(FILE_WRITE_ERR, globals, P_String)); #endif } WriteKeys(globals) Globals *globals; { char *title; long count; char mystr[128]; long *mykeys; short myerr; NumToString(NUMBER_KEYS, mystr); count = strlen(mystr); mystr[count++] = ' '; mykeys = (long *) globals->eventptr; NumToString(mykeys[0], &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = ' '; NumToString(mykeys[1], &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = ' '; NumToString(mykeys[2], &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = ' '; NumToString(mykeys[3], &mystr[count]); /* Returns C string */ count += strlen(&mystr[count]); mystr[count++] = 0x0D; myerr = FSWrite(globals->refnum, &count, mystr); #if DEBUG > 0 if (myerr != noErr) DebugStr(text(FILE_WRITE_ERR, globals, P_String)); #endif } /******* WriteReturn(globals) Globals *globals; { long count; char mystr[50]; count = 1; mystr[0] = 0x0D; FSWrite(globals->refnum, &count, mystr); } ***********/ OpenFile(globals) Globals *globals; { short myerr; char *filename, volname[30]; filename = text(FILE_NAME, globals, C_String); myerr = FSOpen(filename, 0, &globals->refnum); if (myerr != noErr) { DebugStr(text(FILE_OPEN_ERR, globals, P_String)); globals->refnum = 0; } GetVol(volname, &globals->vrefnum); #if DEBUG > 3 DebugStr(text(FILE_NAME, globals, P_String)); #endif #if DEBUG > 3 DebugNum(globals->refnum); DebugNum(globals->vrefnum); #endif } CloseFile(globals) Globals *globals; { short myerr; myerr = FSClose(globals->refnum); if (myerr != noErr) { DebugStr(text(FILE_CLOSE_ERR, globals, P_String)); } FlushVol(NULL, globals->vrefnum); } static int strlen(astr) register char *astr; { register int i; for (i=0; astr[i]; i++); return i; } static void doCtlEvent(theEvent, globals) register EventRecord *theEvent; Globals *globals; /* Pointer to globals passed along the procedure call chain */ { extern void drawWindow(); register WindowPtr myWindow; switch (theEvent->what) { default: break; case updateEvt: myWindow = (WindowPtr) theEvent->message; SetPort(myWindow); BeginUpdate(myWindow); drawWindow(myWindow, globals); EndUpdate(myWindow); break; } return; } /* * Display the contents of the window. * The current port is assumed to be set to the window. */ static void drawWindow(window, globals) WindowPtr window; Globals *globals; /* Pointer to globals passed along the procedure call chain */ { Rect myrect; #if DEBUG > 3 DebugStr(text(DEBUG_UPDATE, globals, P_String)); #endif if (window == nil) return; /* "can't happen" */ myrect = window->portRect; PenNormal(); EraseRect(&myrect); /* InsetRect(&myrect, (short)5, (short)5);*/ /* PaintRect(&myrect);*/ TextMode(srcCopy); TextFont(monaco); TextSize(9); TextFace(bold); /**** MoveTo(10, 15); DrawString(text(EVENTSTR, globals, C_String)); printNum(globals->lastevent); *****/ MoveTo(10, 15); DrawString(text(COUNTSTR, globals, C_String)); printNum((int) globals->count); return; } static printNum(num) int num; { char numStr[32]; TextFace(normal); NumToString(num, numStr); /* Returns C string */ DrawString(numStr); TextFace(bold); return; } #if DEBUG > 0 static DebugNum(num) int num; { char numStr[30]; NumToString(num, numStr); /* Returns C String */ c2pstr(numStr); DebugStr(numStr); return; } static DebugPtr(ptr) char *ptr; { char numStr[30]; if (! Option()) return; NumToString((long)ptr, numStr); /* Returns C String */ c2pstr(numStr); DebugStr(numStr); return; } #endif strcat(str1, str2) register char *str1, *str2; { while (*str1) str1++; while (*str2) *str1++ = *str2++; *str1 = 0; } c2pstr(str) register char *str; { register int i; int length; for (i=0; str[i]; i++); for (length=i; i; i--) str[i] = str[i-1]; str[0] = (unsigned char) length; } static char * text(index, globals, pstrflag) int index; Globals *globals; /* Pointer to globals passed along the procedure call chain */ int pstrflag; /* T - Pascal string. C - C String. */ { GetIndString(globals->strBuf, globals->rsrcID, index); /* Returns C String */ if (pstrflag) c2pstr(globals->strBuf); return(globals->strBuf); } #define PeriodDown (*((char *)0x179) == 0x80) #define AppleDown (*((char *)0x17A) == 0x80) #define OptionDown (*((char *)0x17B) == 0x04) CmdPeriod(globals) Globals *globals; { if (AppleDown && PeriodDown) return true; else return false; } Option() { return OptionDown; } ------------------------------------------------------------- Tim Endres | time@ice.com ICE Engineering | uupsi!ice.com!time 8840 Main Street | Voice FAX Whitmore Lake MI. 48189 | (313) 449 8288 (313) 449 9208 -------- USENET: A slow moving self parody.....