/* * CKMKEY.C * * Key-Config is a keyboard configurator program for use with Columbia's * MacKermit. * * Bill Schilit, April 1985 * * * Copyright (C) 1985, Trustees of Columbia University in the City of * New York. Permission is granted to any individual or institution to * use, copy, or redistribute this software so long as it is not sold * for profit, provided this copyright notice is retained. * */ #include "mac/quickdraw.h" /* order does matter */ #include "mac/osintf.h" /* on these... */ #include "mac/toolintf.h" #include "mac/packintf.h" #include "ckmkey.h" #include "ckmkkc.h" KSHDL kshdl; SFReply sfr; /* global... */ OsType kermtype = {"KERM"}; OsType texttype = {"TEXT"}; char ttype[] = "TEXT"; /* want's to be long aligned */ int quit; MenuHandle menus[MAX_MENU+1]; char MSET_TYPE[] = {"MSET"}, FSET_TYPE[] = {"FSET"}, KSET_TYPE[] = {"KSET"}, *FSET_NAME = {"Kermit function keys"}, *MSET_NAME = {"Kermit meta key prefix"}, *KSET_NAME = {"Kermit Keys"}; BOOL modified; /* if changes have been made */ /* gethdl - return a control handle given a resource ID */ Handle gethdl(item,dp) DialogPtr dp; { int itype; Rect ibox; Handle ihdl; GetDItem(dp,item,&itype,&ihdl,&ibox); return(ihdl); } /* mapkey - accepts a scan code plus modifier bits and translate this * into an 8 bit ascii character using the KSET in ourkey. */ #define LC_IDX 0 /* use lower case map */ #define UC_IDX 1 /* use upper case map */ CHAR mapkey(scode,mods,ismeta,isfkey) BOOL *ismeta,*isfkey; { CHAR c; /* returned char (unsigned) */ int casidx = LC_IDX; /* assume lower case */ if (scode < 0 || scode > MAX_SCODE) printerr("Scan code not in range: ",scode); if (mods & shiftKey) /* shift depressed? */ casidx = UC_IDX; /* yes, select an upper case map */ if (mods & (*kshdl)->ctrlmods) /* control? */ c = (*kshdl)->ctrlmap[casidx][scode]; /* yes, use control table */ else if (mods & (*kshdl)->caplmods) /* else is it caps lock? */ c = (*kshdl)->caplmap[casidx][scode]; /* yes, use caps lock table */ else c = (*kshdl)->normmap[casidx][scode]; /* else it is a normal character */ *ismeta = (mods & (*kshdl)->metamods) ? /* tell about meta */ TRUE : FALSE; *isfkey = (c & FKEYBIT) ? /* tell about function keys */ TRUE : FALSE; return(c & ~FKEYBIT); /* and return the character */ } /* setmapkey - given a scan code, modifiers, and an 8 bit value, store * the value in the appropriate cell of our KSET (ourkset). */ setmapkey(val,scode,mods) CHAR val; /* 8-bit unsigned char */ { int casidx = LC_IDX; if (scode < 0 || scode > MAX_SCODE) printerr("Scan code not in range: ",scode); if (mods & shiftKey) /* shift depressed? */ casidx = UC_IDX; /* yes, select an upper case map */ if (mods & (*kshdl)->ctrlmods) /* control? */ (*kshdl)->ctrlmap[casidx][scode] = val; /* yes, use control table */ else if (mods & (*kshdl)->caplmods) /* else is it caps lock? */ (*kshdl)->caplmap[casidx][scode] = val; /* yes, use caps lock table */ else (*kshdl)->normmap[casidx][scode] = val; /* else it is a normal character */ } printerr(s,n) char *s; { char num[10]; if (n != 0) { NumToString(n,num); ParamText(s,num,"",""); } else ParamText(s,"","",""); CautionAlert(OUR_ALRT,NILPROC); } fatal(s,n) char *s; { printerr(s,n); ExitToShell(); } /* support routines for modifier key dialog */ #define NILCLS 0 /* classes... */ #define OPTCLS 1 /* optionKey */ #define CMDCLS 2 /* cmdKey */ #define KLKCLS 3 /* alphaLock */ int normjunk, caplbits, ctrlbits, metabits; /* restb - table for table driven dialog */ struct restb { int rid, rclass, /* class */ *rcell, /* location of "home" */ rbitv; /* bit value (alphaKey, etc.) */ ControlHandle rhdl; /* handle to this control */ } rsmktb[] = { {RSMK_OPTNORM,OPTCLS,&normjunk,0,NILCTRL}, {RSMK_OPTCTRL,OPTCLS,&ctrlbits,optionKey,NILCTRL}, {RSMK_OPTCAPS,OPTCLS,&caplbits,optionKey,NILCTRL}, {RSMK_OPTMETA,NILCLS,&metabits,optionKey,NILCTRL}, {RSMK_CMDNORM,CMDCLS,&normjunk,0,NILCTRL}, {RSMK_CMDCTRL,CMDCLS,&ctrlbits,cmdKey,NILCTRL}, {RSMK_CMDCAPS,CMDCLS,&caplbits,cmdKey,NILCTRL}, {RSMK_CMDMETA,NILCLS,&metabits,cmdKey,NILCTRL}, {RSMK_KLKNORM,KLKCLS,&normjunk,0,NILCTRL}, {RSMK_KLKCTRL,KLKCLS,&ctrlbits,alphaLock,NILCTRL}, {RSMK_KLKCAPS,KLKCLS,&caplbits,alphaLock,NILCTRL}, {RSMK_KLKMETA,NILCLS,&metabits,alphaLock,NILCTRL} }; #define RSMKZ (sizeof (rsmktb)/sizeof(struct restb)) Handle getdlghdl(dp,rid) DialogPtr dp; { int itemtype; Rect itembox; Handle itemhdl; GetDItem(dp,rid,&itemtype,&itemhdl,&itembox); return(itemhdl); } /* rmskinit - initialize "set modifier key" dialog, find control * handles for each item, hilite "normal" for each * class and then re-hilite any actual settings. */ rsmkinit(dp) DialogPtr dp; { int r; caplbits = (*kshdl)->caplmods; metabits = (*kshdl)->metamods; ctrlbits = (*kshdl)->ctrlmods; for (r=0; r < RSMKZ; r++) rsmktb[r].rhdl = (ControlHandle) getdlghdl(dp,rsmktb[r].rid); rsmksetcls(RSMK_OPTNORM); rsmksetcls(RSMK_KLKNORM); rsmksetcls(RSMK_CMDNORM); for (r=0; r < RSMKZ; r++) if (rsmktb[r].rbitv & *rsmktb[r].rcell) rsmksetcls(rsmktb[r].rid); } /* rsmkfinish - finish up "set modifier key" dialog. Store results * into cells */ rsmkfinish() { int r; metabits = caplbits = ctrlbits = 0; for (r=0; r < RSMKZ; r++) if (GetCtlValue(rsmktb[r].rhdl)) *rsmktb[r].rcell |= rsmktb[r].rbitv; /* turn on the bit */ (*kshdl)->metamods = metabits; (*kshdl)->caplmods = caplbits; (*kshdl)->ctrlmods = ctrlbits; } rsmksetcls(item) { int r,cls; for (r=0; r < RSMKZ; r++) /* find the class */ if (rsmktb[r].rid == item) { cls = rsmktb[r].rclass; if (cls == NILCLS) /* toggle? */ SetCtlValue(rsmktb[r].rhdl,!GetCtlValue(rsmktb[r].rhdl)); else SetCtlValue(rsmktb[r].rhdl,btnOn); break; } if (cls != NILCLS) /* if there is a class (skip meta) */ for (r=0; r < RSMKZ; r++) if (rsmktb[r].rid != item && rsmktb[r].rclass == cls) SetCtlValue(rsmktb[r].rhdl,btnOff); } metaradios(use8,dlg) DialogPtr dlg; { SetCtlValue(getctlhdl(RSMK_M8BIT,dlg),(use8) ? btnOn : btnOff); SetCtlValue(getctlhdl(RSMK_MPREF,dlg),(use8) ? btnOff : btnOn); } BOOL metafinish(use8,dlg) DialogPtr dlg; { char mtxt[256]; Handle mhdl; int l,sb,se; GetIText(gethdl(RSMK_METXT,dlg),mtxt); /* get meta text itself */ if (use8) /* want to use 8 bit? */ mtxt[0] = l = 0; /* yes, use zero length string */ else { /* else check out meta text */ if (!chkcodestr(mtxt,&sb,&se)) { /* error in backslash? */ SelIText(dlg,RSMK_METXT,sb,se); /* yes, set selection range */ SysBeep(2); /* tell them */ return(FALSE); /* and indicate failure */ } l = decodestr(mtxt); /* decode in place, get length */ } (*kshdl)->meta8bit = use8; /* update boolean */ mhdl = (*kshdl)->metahdl; /* get old meta text handle */ DisposHandle(mhdl); /* rid old handle */ mhdl = NewHandle(l+1); /* string size plus size byte */ BlockMove(mtxt,*mhdl,l+1); /* copy the string */ return(TRUE); /* and return ok */ } dosetmkdialog() { int itemhit,m8bit; DialogPtr dlg; Handle mhdl; char *mstr,*encodestr(); dlg = GetNewDialog(DLOG_RSMK,NILPTR,(WindowPtr) -1); mhdl = (*kshdl)->metahdl; /* get meta string */ HLock(mhdl); /* prevent movement */ mstr = encodestr(*mhdl); /* encode it */ HUnlock(mhdl); /* unlock */ SetIText(gethdl(RSMK_METXT,dlg),mstr); /* set it */ DisposPtr(mstr); /* no longer needed */ rsmkinit(dlg); /* init settings */ m8bit = (*kshdl)->meta8bit; /* get 8 bit quote value */ metaradios(m8bit,dlg); /* init radio items */ ShowWindow(dlg); for (;;) { ModalDialog(NILPROC,&itemhit); switch (itemhit) { case RSMK_OK: if (!metafinish(m8bit,dlg)) /* do meta stuff */ break; /* format error... */ modified = TRUE; /* things have changed */ rsmkfinish(); /* store values */ case RSMK_CANCEL: DisposDialog(dlg); return; case RSMK_M8BIT: case RSMK_MPREF: m8bit = (itemhit == RSMK_M8BIT); metaradios(m8bit,dlg); break; default: rsmksetcls(itemhit); /* set buttons */ break; } } } /* privrsrc - return a private copy of a resource. The handle * returned is relocatable but non purgeable. * */ Handle privrsrc(type,id,name) char *type,*name; { Handle rhdl,phdl; char errbuf[256]; int l; rhdl = GetResource(type,id); /* load the resource */ if (rhdl == (Handle) NIL) /* nothing? */ { strcpy(errbuf,"There are no "); strcat(errbuf,name); strcat(errbuf," of the known version in this file."); printerr(errbuf,0); return((Handle) NIL); /* then return now with NIL */ } HLock(rhdl); /* make sure rsrc stays around */ phdl = NewHandle(l = SizeResource(rhdl)); /* get new relocatable block */ HLock(phdl); /* lock new block also */ BlockMove(*rhdl,*phdl,l); /* copy from resource to new block */ HUnlock(rhdl); /* rsrc lock no longer needed */ ReleaseResource(rhdl); /* rsrc completely gone now */ HNoPurge(phdl); /* keep new block in memory */ HUnlock(phdl); /* but can move around */ return(phdl); /* all done */ SYM(PRIVRESOURCE); } KSHDL loadkset() { Handle fhdl,mhdl; KSHDL khdl; khdl = (KSHDL) privrsrc(KSET_TYPE,KSVER,KSET_NAME); if (khdl == (KSHDL) NIL) return((KSHDL) NIL); fhdl = privrsrc(FSET_TYPE,KSVER,FSET_NAME); if (fhdl == (Handle) NIL) return((KSHDL) NIL); (*khdl)->fcnshdl = fhdl; /* save handle to relocatable block */ mhdl = privrsrc(MSET_TYPE,KSVER,MSET_NAME); if (mhdl == (Handle) NIL) return((KSHDL) NIL); (*khdl)->metahdl = mhdl; /* save handle */ return(khdl); /* return the KSET handle */ SYM(LOADKSET); } /* * initmenus - create the menu bar. * */ initmenus() { int i; for (i=MIN_MENU; i<=MAX_MENU; i++) /* For all menus */ { menus[i] = GetMenu(i); /* Fetch it from resource file */ InsertMenu(menus[i],0); /* Put it on menu line */ } DrawMenuBar(); /* Finish up by displaying the bar */ return; SYM(INITMENUS); } addrsrc(type,id,hdl,str) char *type,*str; Handle hdl; { Handle rhdl; rhdl = GetResource(type,id); /* check for old value */ if (rhdl != NULL) { /* something there? */ RmveResource(rhdl); /* yes, then delete it */ if (ResError() != noErr) return(!syserr(ResError())); } AddResource(hdl,type,id,str); return(!syserr(ResError())); /* return TRUE if ok */ } /* kfilefilter - match creator "KERM" from sfgetfile call */ kfilefilter() { FileParam *pb; /* args from SFGetFile... */ char *retval; retval = (char *) getpargs(&pb,sizeof(FileParam *)); *retval = (strncmp( /* compare creator's... and return */ pb->ioFlFndrInfo.fdCreator.s, /* TRUE if not a match */ kermtype.s,4) != 0); /* FALSE otherwise for inclusion */ return; SYM(KFILEFILTER); } savevals(fname,fvol) char *fname; { int rfnum; SetVol(NILPTR,fvol); /* set volume */ rfnum = OpenResFile(isapstr(fname)); /* open it up */ if (rfnum == -1) /* could not? */ { syserr(ResError()); /* handle error */ return; /* and return */ } if (addrsrc(MSET_TYPE,KSVER,(*kshdl)->metahdl,MSET_NAME)) if (addrsrc(FSET_TYPE,KSVER,(*kshdl)->fcnshdl,FSET_NAME)) (addrsrc(KSET_TYPE,KSVER,(Handle) kshdl,KSET_NAME)); CloseResFile(rfnum); if (syserr(ResError())) /* error occured */ return; FlushVol(NILPTR,fvol); /* flush the volume */ rfnum = OpenResFile(isapstr(fname)); /* reopen the file */ if (rfnum == -1) /* unable? */ { syserr(ResError()); return; } kshdl = loadkset(); /* load in files KSET */ CloseResFile(rfnum); /* close the file */ if (kshdl == NIL) /* problems */ fatal("Unable to reload key defs!",0); modified = FALSE; /* no longer modified */ return; SYM(SAVEVALS); } loadvals() { Point where; int rfnum; SetPt(&where,75,115); SFGetFile(&where,"Load variables from:", kfilefilter,1,ttype,NILPROC,&sfr); if (!sfr.good) /* did they hit cancel? */ return(FALSE); /* yes, so return now */ SetVol(NILPTR,sfr.vRefNum); /* setup volume */ rfnum = OpenResFile(isapstr(sfr.fName)); /* open up the file */ if (rfnum == -1) /* unable? */ return(!syserr(ResError())); kshdl = loadkset(); /* load in files KSET */ CloseResFile(rfnum); /* close the file */ if (kshdl == (KSHDL) NIL) return(FALSE); else return(TRUE); SYM(LOADVALS); } /* * aboutme - Display the about KCONFIG dialog box, wait for user to * hit the OK button (maybe this should be a mouse click). * * The KCONFIG version string is stored in the resource fork as type * "KERK" ID 0 -- load this resource into memory, and lock it. The * resource is locked so that we won't go off the deep end if the * heap gets compacted during the dialog display. This would cause * problems because we are using the de-referenced handle, the actual * location of the string and not a pointer (handle) to it. * */ aboutme() { Handle kversion; static char ktype[] = "KERK"; DialogPtr kdialog; /* our dialog */ kversion = GetResource(ktype,0); /* get version information */ LoadResource(kversion); /* make sure loaded */ HLock(kversion); /* prevent movement */ ParamText(isapstr(*kversion),"","",""); /* set it up for display via ^0 */ /* de-reference the handle */ kdialog = GetNewDialog(ABOUTID,NILPTR,(WindowPtr) -1); ShowWindow(kdialog); /* in case hidden or something */ DrawDialog(kdialog); /* draw the dialog */ while (!Button()); /* wait for button */ DisposDialog(kdialog); /* dispose dialog box */ HUnlock(kversion); /* undo previous HLock */ ReleaseResource(kversion); /* no longer needed */ } /* maybesave - enter maybe save dialog. * * Pass the name of the operation which will zap things, for example * "quitting" or "opening" and we'll tell the user about the pending * doom of changes if they've occured. We return TRUE if user wants * to proceed, FALSE otherwise. * */ BOOL maybesave(op) char *op; { if (!modified) return; /* no changes made */ ParamText(isapstr(sfr.fName),op,"",""); /* set name, operation */ switch (Alert(MAYBE_ALRT,NILPROC)) { case YES_MAYBE: savevals(sfr.fName,sfr.vRefNum); /* YES: do it */ case NO_MAYBE: return(TRUE); /* NO: proceed */ } return(FALSE); /* Cancel or other... */ } parser() { EventRecord ev; WindowPtr evw; for (quit = FALSE; !quit;) { SystemTask(); GetNextEvent(everyEvent,&ev); if (ev.what == mouseDown) { switch (FindWindow(&ev.where,&evw)) { case inMenuBar: menuparser(MenuSelect(&ev.where)); HiliteMenu(0); /* done so un-hilite */ break; case inSysWindow: SystemClick(&ev,evw); break; } } } } alterofferings(savok) { int (*fcn)(),EnableItem(),DisableItem(); char savbuf[256]; fcn = (savok) ? EnableItem : DisableItem; (*fcn)(menus[SETK_MENU],0); /* enable/disable SET menu */ (*fcn)(menus[FILE_MENU],SAVE_FILE); /* enable/disable SAVE item */ (*fcn)(menus[FILE_MENU],DECOM_FILE); /* enable/disable DECOMPILE... */ strcpy(savbuf,"Save "); /* initial text of save */ if (savok) /* ok to save? */ strncat(savbuf,&sfr.fName[1],sfr.fName[0]); /* yes... put in name */ SetItem(menus[FILE_MENU],SAVE_FILE,savbuf); /* set item */ HiliteMenu(0); /* de-hilite, prevents oddness */ DrawMenuBar(); /* disable/enable menu bar items */ } menuparser(mitem) { int menu = HiWord(mitem), item = LoWord(mitem); switch (menu) { case APPL_MENU: switch (item) { case ABOU_APPL: aboutme(); break; default: break; } break; case FILE_MENU: switch (item) { case OPEN_FILE: if (maybesave("opening")) /* if they want... */ alterofferings(loadvals()); /* do it and alter menu items */ break; case DECOM_FILE: p2cstr(sfr.fName); decomdialog(sfr.fName); c2pstr(sfr.fName); break; case SAVE_FILE: savevals(sfr.fName,sfr.vRefNum); /* do it */ break; case QUIT_FILE: if (maybesave("quitting")) /* if they really want to */ quit = TRUE; /* then let them */ break; } break; case SETK_MENU: switch (item) { case SKEY_SETK: ScrDmpEnb = scrdmpdisabled; /* disable special keys */ setkeydialog(); ScrDmpEnb = scrdmpenabled; /* enable special keys */ break; case SMOD_SETK: dosetmkdialog(); break; case FCNK_SETK: setfkeydialog(); break; } break; } } /* checks for system error, returns FALSE if noErr, else puts up an error * message with an understandable text string. * */ struct { int errnum; char *errstr; } ioerrs[] = { {resNotFound,"Resource not found"}, {resFNotFound,"Resource file not found"}, {addResFailed,"AddResource failed"}, {dirFulErr,"Directory is full"}, {dskFulErr,"Disk is full"}, {wPrErr,"Diskette is write protected"}, {fLckdErr,"File is software locked"}, {vLckdErr,"Volume is software locked"}, {fBsyErr,"File is busy"}, {opWrErr,"File is already open with write permission"}, {0,NILPTR} }; syserr(err) { int e; if (err == noErr) return(FALSE); for (e = 0; ioerrs[e].errnum != 0 && ioerrs[e].errnum != err; e++); if (ioerrs[e].errstr == NILPTR) /* anything there? */ printerr("Unknown IO error: ",err); else printerr(ioerrs[e].errstr,0); return(TRUE); SYM(SYSERR); } main() { QD = &QDVar; InitGraf(&thePort); InitWindows(); InitFonts(); InitDialogs(NILPROC); InitMenus(); TEInit(); InitCursor(); initmenus(); alterofferings(FALSE); /* disable menu items */ modified = FALSE; /* not modified */ parser(); ExitToShell(); SYM(MAIN); }