page@swan.ulowell.edu (Bob Page) (12/11/88)
Submitted-by: scott@applix.uucp (Scott Evernden) Posting-number: Volume 2, Issue 95 Archive-name: intuition/snipit12.1 - SnipIt 1.2 - SnipIt is an input handler wedge which allows you to clip text from any window, and then paste that text anywhere, as though you had typed it on the keyboard. New in SnipIt 1.2 are the following: o Now attempts to work in all windows and consoles. P-Edit and VT100 now can be snipped from. o Automatically detaches itself and runs in the background- no Run/RunBack required. o Built-in mini help (type: snipit h). o Keyboard option to insert a short string at the beginning of each pasted line. o Options to move/adjust/correct snip/recognizer cell area independently for consoles and windows. o Can recognize highlighted text. o Option to freeze window layer while snipping. # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # readme # makefile # hs.h # detach.c # hand.c # main.c # patch.c # reco.c # snipit.keys # patch.doc # snipit.doc # This archive created: Sun Dec 11 00:43:21 1988 cat << \SHAR_EOF > readme - SnipIt 1.2 - SnipIt is an input handler wedge which allows you to clip text from any window, and then paste that text anywhere, as though you had typed it on the keyboard. New in SnipIt 1.2 are the following: o Now attempts to work in all windows and consoles. P-Edit and VT100 now can be snipped from. o Automatically detaches itself and runs in the background- no Run/RunBack required. o Built-in mini help (type: snipit h). o Keyboard option to insert a short string at the beginning of each pasted line. o Options to move/adjust/correct snip/recognizer cell area independently for consoles and windows. o Can recognize highlighted text. o Option to freeze window layer while snipping. - Scott Evernden SHAR_EOF cat << \SHAR_EOF > makefile CFLAG = LFLAGS = -w CFLAGS = $(CFLAG) +ihs.i OBJS = main.o hand.o reco.o snipit: $(OBJS) detach.o ln $(LFLAGS) -o $* $(OBJS) detach.o -lc beep detach.o: detach.c $(OBJS): hs.i hs.i: hs.h cc -o nil: +hhs.i hs.h final: @make LFLAGS= SHAR_EOF cat << \SHAR_EOF > hs.h #include <exec/types.h> #include <exec/ports.h> #include <exec/memory.h> #include <exec/devices.h> #include <exec/execbase.h> #include <exec/interrupts.h> #include <graphics/gfxbase.h> #include <intuition/intuition.h> #include <intuition/intuitionbase.h> #include <libraries/dos.h> #include <libraries/dosextens.h> #include <devices/conunit.h> #include <devices/keymap.h> #include <devices/input.h> #include <devices/inputevent.h> struct ConsoleBase { struct Device conDevice; char reserved[26]; struct List conUnits; }; #include <functions.h> /* mouse states */ #define M_UP 0 #define M_MOVE 1 #define M_DOWN 2 /* 'snip' container defines */ #define CON_SNIP 1 #define WIN_SNIP 2 #define PRE_SIZE 32 SHAR_EOF cat << \SHAR_EOF > detach.c /* Copyright (C) 1986,1987 by Manx Software Systems, Inc. */ /* Hacked up for SnipIt 1.2 use - Scott Evernden */ #include <exec/memory.h> #include <libraries/dosextens.h> #include <functions.h> struct Process *_FindTask(); void *_AllocMem(); long _Open(); #define STACK_SIZE 3000L extern BPTR output; extern long running; extern char *_procname; extern char *_detach_name; static long _alen = 0; static char *_aptr = 0; #asm dseg public __savsp cseg #endasm do_detach(alen, aptr) long *alen; char **aptr; { register struct CommandLineInterface *cli; register struct Process *pp; register unsigned short c; register char *cp; register long l; long *lp, *sav; struct MemList *mm; pp = _FindTask(0L); /* first time through!! */ if (pp->pr_CLI) { cli = (struct CommandLineInterface *) ((long)pp->pr_CLI << 2); l = cli->cli_Module; output = (BPTR) _Open("*", MODE_OLDFILE); _alen = *alen; _aptr = _AllocMem(_alen, 0L); movmem(*aptr, _aptr, (int)_alen); cp = (char *)((long)cli->cli_CommandName << 2); _detach_name = AllocMem((long)cp[0]+1, 0L); movmem(cp, _detach_name, cp[0]+1); #asm move.l __savsp,-(sp) #endasm cli->cli_Module = 0; CreateProc(_procname, 0L, l, STACK_SIZE); while (running == 0) Delay(5L); #asm move.l (sp)+,sp move.l #0,d0 rts #endasm } /* second time through */ else if (strcmp(pp->pr_Task.tc_Node.ln_Name, _procname) == 0) { lp = (long *)((long)pp->pr_SegList << 2); lp = (long *)(lp[3] << 2); sav = lp; c = 2; while (lp) { lp = (long *)(*lp << 2); c++; } mm = _AllocMem((long)sizeof(struct MemList)+ (c-1)*sizeof(struct MemEntry), 0L); lp = sav; mm->ml_NumEntries = c; c = 0; while (lp) { mm->ml_me[c].me_Addr = (APTR)lp - 1; mm->ml_me[c].me_Length = lp[-1]; lp = (long *)(*lp << 2); c++; } mm->ml_me[c].me_Addr = (APTR)_aptr; mm->ml_me[c++].me_Length = _alen; mm->ml_me[c].me_Addr = (APTR)_detach_name; mm->ml_me[c++].me_Length = _detach_name[0] + 1; AddTail(&((struct Task *)pp)->tc_MemEntry, mm); *alen = _alen; *aptr = _aptr; } } SHAR_EOF cat << \SHAR_EOF > hand.c /* :ts=4 * * Amiga SnipIt 1.2 * (c) (opyright 1987,1988 - Scott Evernden - All Rights Reserved * * hand.c - input event handler & snipper & lib function replacements * */ #include "hs.h" int state; /* mouse state */ int snip; /* container type which is highlighted */ int maxx, maxy; /* maximum cells in snipped layer */ int origx, origy; /* pixel origin in conunit */ int charx, chary; /* pixel size of char cell of conunit */ int lastx, lasty; /* last cell highlighted */ int con_offx, con_offy; /* correction offsets for console windows */ int win_offx, win_offy; /* correction offsets for non-console windows */ int snipx[2], snipy[2]; /* snip area; top/left to bottom/right */ int left, right; /* sides of snip area, irrespective of rows */ struct TextFont *capttf; /* non-NULL indicates recognition required */ struct Window *snipw; /* clipped text window */ struct RastPort *sniprp; /* rastport of clipped text window */ struct RastPort captrp; /* rastport holding clipped snip area */ struct BitMap captbm; /* bitmap into which snipped area is copied */ int captx, capty; /* dimensions of capture map */ int jobFlag; /* flag input handler to ignore mouse events */ int lock_layer; /* lock window/console layer while snipping */ int windows=1; /* include windows in layer search */ int cmd1 = IEQUALIFIER_LCOMMAND; int cmd2 = IEQUALIFIER_LALT; extern struct IntuitionBase *IntuitionBase; extern struct ConsoleBase *ConsoleBase; extern struct Task *myTask; extern int mySignal; /* this does one at a time */ struct InputEvent *doEvent(); /*********************************************/ #asm public _geta4 ; Trap these Gfx/Intui functions; purpose is to remove hilighting, if nec. ; Not all possible cases are handled (window resizing, for example), but ; the most common ones are. public _myRectFill public _myScrollRaster public _myCloseWindow public _oldRectFill public _oldScrollRaster public _oldCloseWindow _myRectFill: ; pardon me move.l a4,-(sp) jsr _geta4 ; establish addressing tst.w _snip beq.s 1$ ; no highlighted area; get out cmpa.l _sniprp,a1 bne.s 1$ ; not the same RastPort; get out movem.l a1/d0-d5,-(sp) jsr _clearHi ; de-highlight movem.l (sp)+,a1/d0-d5 1$: movea.l _oldRectFill,a0 movea.l (sp)+,a4 jmp (a0) ; continue into library _myScrollRaster: ; 'scuse move.l a4,-(sp) jsr _geta4 tst.w _snip beq.s 1$ cmpa.l _sniprp,a1 bne.s 1$ movem.l a1/d0-d5,-(sp) jsr _clearHi movem.l (sp)+,a1/d0-d5 1$: movea.l _oldScrollRaster,a0 movea.l (sp)+,a4 jmp (a0) _myCloseWindow: move.l a4,-(sp) jsr _geta4 tst.w _snip beq.s 1$ cmpa.l _snipw,a0 bne.s 1$ ; not the same Window; get out clr.w _snip clr.l _capttf ; Window closing; reset indicators 1$: movea.l _oldCloseWindow,a1 movea.l (sp)+,a4 jmp (a1) ;************************ ; input event stream glue public _handlerCode _handlerCode: movem.l d2/d3/a0/a1/a4/a6,-(sp) ; i think this is right jsr _geta4 jsr _myHandler movem.l (sp)+,d2/d3/a0/a1/a4/a6 rts #endasm /*********************************************/ /* SnipIt's input event handler */ struct InputEvent *myHandler(d2, d3, ev) long d2, d3; register struct InputEvent *ev; { register struct InputEvent *inev, **evp; struct InputEvent *outev; if (jobFlag) return ev; inev = ev; outev = NULL; /* back-pointer */ evp = &outev; /* * Loop thru the possibly linked list of events. * We remove the ones having meaning to SnipIt, and leave the others */ while (inev) { ev = inev; inev = ev->ie_NextEvent; /* ensure that main code isn't running and this is a mouse event */ if (ev->ie_Class == IECLASS_RAWMOUSE) ev = doEvent(ev); /* patch back-pointer */ if (*evp = ev) evp = &ev->ie_NextEvent; } /* pass 'em along */ return outev; } /*********************************************/ /* handle a single (mouse) input event */ struct InputEvent *doEvent(ev) register struct InputEvent *ev; { static int lflag, rflag, cmd; register UWORD code; register int x, y; x = ev->ie_X; y = ev->ie_Y; code = ev->ie_Code; /* in mid-snip? */ if (lflag && code == IECODE_NOBUTTON && (ev->ie_Qualifier & IEQUALIFIER_LEFTBUTTON)) { mouse(M_MOVE, x, y); return ev; } /* button transition event... */ code &= ~IECODE_UP_PREFIX; /* mouse button down event? */ if ((ev->ie_Code & IECODE_UP_PREFIX) == 0) { if (cmd = ev->ie_Qualifier & (cmd1 | cmd2)) { if (!rflag && code == IECODE_LBUTTON) { lflag++; mouse(M_DOWN, x, y); } else if (!lflag && code == IECODE_RBUTTON) rflag++; /* note transition */ return NULL; } } /* release of left mouse button? */ else if (lflag && code == IECODE_LBUTTON) { lflag = 0; mouse(M_UP, x, y); return NULL; } /* release of right mouse button? */ else if (rflag && code == IECODE_RBUTTON) { rflag = 0; /* kick main code */ jobFlag = cmd; Signal(myTask, 1L << mySignal); return NULL; } /* event back into stream */ return ev; } /*********************************************/ /* find a console containing the layer holding (x,y); return success flag */ int whichConsole(layer, x, y) struct Layer *layer; int x, y; { register struct ConUnit *cu, *rcu; register struct Node *node; /* result conunit */ rcu = NULL; _Forbid(); /* begin at the beginning */ node = ConsoleBase->conUnits.lh_Head; /* next is NULL when back at listhead */ while (node->ln_Succ) { cu = (struct ConUnit *) node; /* see if console window's layer is the same */ if (cu && cu->cu_Window && cu->cu_Window->RPort->Layer == layer) { rcu = cu; /* found it */ break; } node = node->ln_Succ; } Permit(); if (rcu) { snip = CON_SNIP; snipw = rcu->cu_Window; sniprp = snipw->RPort; charx = rcu->cu_XRSize; chary = rcu->cu_YRSize; origx = rcu->cu_XROrigin; origy = rcu->cu_YROrigin; maxx = rcu->cu_XMax; maxy = rcu->cu_YMax; } return rcu != NULL; } /*********************************************/ /* find a window containing the layer holding (x,y); return success flag */ int whichWindow(s, layer, x, y) struct Screen *s; struct Layer *layer; int x, y; { register struct Window *w, *rw; if (!windows) return NULL; /* result window */ rw = NULL; _Forbid(); w = s->FirstWindow; while (w) { if (w->WLayer == layer) { rw = w; break; } w = w->NextWindow; } Permit(); if (rw) { snip = WIN_SNIP; snipw = rw; sniprp = snipw->RPort; charx = sniprp->Font->tf_XSize; chary = sniprp->Font->tf_YSize; origx = rw->BorderLeft; origy = rw->BorderTop; maxx = (rw->Width - rw->BorderRight - origx) / charx - 1; maxy = (rw->Height - rw->BorderBottom - origy) / chary - 1; } return rw != NULL; } /*********************************************/ /* handle meaningful mouse activity */ mouse(event, mx, my) int event; register int mx, my; { static struct Screen *s; static struct Layer *layer; if (event == M_DOWN) s = IntuitionBase->FirstScreen; /* correct raw positions according to this screen */ if (!(s->ViewPort.Modes & LACE)) my /= 2; mx += s->MouseX - 2; /* accumulate deltas */ my += s->MouseY - 1; /* x,y adjusted for feel */ if (event == M_DOWN) { /* de-hilight, if nec. */ if (snip) hiSnip(0); /* turn flag off */ snip = 0; /* locate pointed-at layer */ if ((layer = WhichLayer(&s->LayerInfo, (long) mx, (long) my)) && (whichConsole(layer, mx, my) || whichWindow(s, layer, mx, my))) { /* if mouse down in title line area, remain clear */ if (my - snipw->TopEdge < origy) snip = 0; } } /* nothing interesting */ if (!snip) return; /* mouse to window-relative cell coordinates */ mx = (mx - snipw->LeftEdge - origx) / charx; if (mx < 0) mx = 0; else if (maxx < mx) mx = maxx; my = (my - snipw->TopEdge - origy) / chary; if (my < 0) my = 0; else if (maxy < my) my = maxy; /* highlighting games ahead */ if (event == M_DOWN) { state = M_DOWN; if (lock_layer) LockLayerRom(layer); snipx[0] = mx; snipy[0] = my; hiLite(mx, my, 1, 1); } else if (event == M_UP) { snipx[1] = mx; snipy[1] = my; if (state == M_MOVE) hiLite(lastx, lasty, 1, 1); hiLite(snipx[0], snipy[0], 1, 1); hiSnip(charx == 8); state = M_UP; if (charx != 8) /* only able to do 8 pixel wide fonts */ clearHi(); if (lock_layer) UnlockLayerRom(layer); } else if (mx != lastx || my != lasty) { if (state == M_MOVE) hiLite(lastx, lasty, 1, 1); hiLite(lastx = mx, lasty = my, 1, 1); state = M_MOVE; } } /*********************************************/ /* de-highlight; snip is known to be set */ clearHi() { if (state == M_UP) hiSnip(0); else if (lock_layer) return; else { hiLite(snipx[0], snipy[0], 1, 1); if (state == M_MOVE) hiLite(lastx, lasty, 1, 1); } snip = 0; } /*********************************************/ /* local cleanup for this module */ finiHand() { int i; PLANEPTR p; if (snip) clearHi(); if (p = captbm.Planes[0]) FreeRaster(p, (long) captx, (long) capty); } /*********************************************/ /* manufacture rastport with bitmap, ready to receive captured bitmap */ int allocMap(sx, sy) int sx, sy; { PLANEPTR p; /* release previous, if any */ if (p = captbm.Planes[0]) { FreeRaster(p, (long) captx, (long) capty); captbm.Planes[0] = NULL; } /* record new map size */ captx = sx; capty = sy; /* build new bitmap to contain snipped area */ InitBitMap(&captbm, 1L, (long) captx, (long) capty); InitRastPort(&captrp); captrp.BitMap = &captbm; /* allocate bitmap planes */ p = (PLANEPTR) AllocRaster((long) captx, (long) capty); if (!p) return 0; captbm.Planes[0] = p; return 1; } /*********************************************/ /* video reverse the capture area; perform capture if flagged */ hiSnip(capt) int capt; { register int px, py, qx, qy, tx, ty; long ox, oy; /* need these vars to be handy */ tx = maxx; /* take care of backward snip areas */ if (snipy[0] < snipy[1] || snipy[0] == snipy[1] && snipx[0] <= snipx[1]) { px = snipx[0]; py = snipy[0]; qx = snipx[1]; qy = snipy[1]; } else { px = snipx[1]; py = snipy[1]; qx = snipx[0]; qy = snipy[0]; } /* only if capturing more than 1 cell... */ if (capt && (px != qx || py != qy)) { /* left and right sides */ left = px; right = qx; /* get a new bitmap */ if (allocMap((tx + 1) * charx, (qy - py + 1) * chary)) { /* copy console contents into snip-map */ ox = origx; oy = origy + py * chary; if (snip == CON_SNIP) { /* user-specified corrections */ ox += con_offx; oy += con_offy; } else { ox += win_offx; oy += win_offy; } ClipBlit(sniprp, ox, oy, &captrp, 0L, 0L, (long) captx, (long) capty, 0xC0L); /* note new info in snip-map */ capttf = sniprp->Font; } else { /* no memory, act dumb */ snip = captx = capty = 0; return; } } /* perform hilighting */ while (py <= qy) { if (py == qy) tx = qx; hiLite(px, py, tx - px + 1, 1); px = 0; py++; } } /*********************************************/ /* low-lever video reverser */ hiLite(x, y, xs, ys) int x, y, xs, ys; { register long ox, oy; ox = origx + x * charx; oy = origy + y * chary; if (snip == CON_SNIP) { /* user-specified corrections */ ox += con_offx; oy += con_offy; } else { ox += win_offx; oy += win_offy; } ClipBlit(sniprp, ox, oy, sniprp, ox, oy, (long) (xs * charx), (long) (ys * chary), 0x50L); } /*********************************************/ SHAR_EOF cat << \SHAR_EOF > main.c /* :ts=4 * * Amiga SnipIt 1.2 * (c) (opyright 1987,1988 - Scott Evernden - All Rights Reserved * * main.c - cutter/paster like SunTools * * Permission is granted to modify and redistribute as long * as this notice is left intact. * */ /********************** The strategy here begins with the installation of some input handler code into the input event handler chain. This code looks for mouse actions and keyboard presses that indicate that text is being snipped, or is being pasted. Snipped text (plane 0) is always immediately copied into a temp 1-plane bitmap without further processing. Subsequents "snips" cause the old snipped bitmap to be thrown away, and a new one captured. Pasting requires that the text in the capture bitmap be recognized. This is not done in the input handler code, since it would cause all pending input events to pile up while the recognizer is running. Instead, the input handler code signals the main snipit code (RUNning in the background, itself) to do the recognition and fake the kb events. During this period, the input handler code temporarily suspends its special processing waiting for the main code (recognizer) to finish. Once a capture bitmap has been recognized and converted into a sequence of key codes, it is deallocated, and subsequent pastes don't require the recognition step. **********************/ #include "hs.h" struct Task *_FindTask(); struct Library *_OpenLibrary(); BPTR output = 0; long LayersBase; /* for WhichLayer() */ struct GfxBase *GfxBase; struct IntuitionBase *IntuitionBase; struct ConsoleBase *ConsoleBase; /* defined in hs.h */ /* communication with input.device */ struct IOStdReq *inpReq; struct MsgPort *inpPort; /* communication with console.device */ struct MsgPort *conPort; struct IOStdReq *conReq; /* who I am */ struct Task *myTask; /* snipit's port */ struct MsgPort *myPort; struct MyMessage { struct Message m; int done, huh, off; int w_offx, w_offy; int c_offx, c_offy; long alen; char *aptr; } myMsg, *msgp; /* for snipit's input handler */ struct Interrupt handler; /* flags handler installation for cleanup */ int handlerIn; /* snipit's allocated signal bit */ int mySignal = -1L; /* snipit's input handler code */ VOID handlerCode(); /* snipit replacement functions */ VOID myRectFill(), myScrollRaster(), myCloseWindow(); /* remember original library vectors */ long oldRectFill, oldScrollRaster, oldCloseWindow; /* vector offsets of certain functions */ extern int lvoRectFill, lvoScrollRaster, lvoCloseWindow; /* detach stuff */ long running = 0; char *_procname = "\x9B33mSnipIt 1.2\x9B0m"; char *huh_msg = "Huh? (for help type: snipit h)"; /* "Can't open"... forms */ char *i_libname = "~intuition.library"; char *g_libname = "~graphics.library"; char *l_libname = "~layers.library"; char *i_devname = "~input.device"; char *c_devname = "~console.device"; char *port_name = "^\x9B33mSnipIt 1.2\x9B0m Port"; long _savsp; extern int jobFlag; extern int con_offx, con_offy; extern int win_offx, win_offy; extern int cmd1, cmd2; extern int snip, lock_layer, windows; extern char preString[]; /*********************************************/ /* pick up the ABS symbols describing gfx/intui lib offsets */ #asm dseg public _LVORectFill public _LVOScrollRaster public _LVOCloseWindow _lvoRectFill dc.w _LVORectFill _lvoScrollRaster dc.w _LVOScrollRaster _lvoCloseWindow dc.w _LVOCloseWindow cseg #endasm /*********************************************/ writes(str) register char *str; { register char *piece; register long len; len = 0; if (*str == '!') { piece = "Can't "; len = 6; } else if (*str == '~') { piece = "Can't open "; len = 11; } else if (*str == '^') { piece = "Can't create "; len = 13; } else if (*str == '_') { piece = _procname; len = 17; } if (len) { str++; _Write(output, piece, len); } /* output a message & newline */ _Write(output, str, (long) strlen(str)); _Write(output, "\n", 1L); } /*********************************************/ fini() { long stat; /* cleanup in other modules */ finiHand(); finiReco(); /* restore gfx/intui library vectors */ if (oldRectFill) SetFunction(GfxBase, (long) lvoRectFill, oldRectFill); if (oldScrollRaster) SetFunction(GfxBase, (long) lvoScrollRaster, oldScrollRaster); if (oldCloseWindow) SetFunction(IntuitionBase, (long) lvoCloseWindow, oldCloseWindow); /* remove snipit input handler */ if (handlerIn) { inpReq->io_Command = IND_REMHANDLER; inpReq->io_Data = (APTR) &handler; DoIO(inpReq); } /* close down console.device */ if (conReq) { if (conReq->io_Device) CloseDevice(conReq); DeleteStdIO(conReq); } if (conPort) DeletePort(conPort); /* close down input.device */ if (inpReq) { if (inpReq->io_Device) CloseDevice(inpReq); DeleteStdIO(inpReq); } if (inpPort) DeletePort(inpPort); /* release snipit's port & signal bit */ if (myPort) DeletePort(myPort); if (mySignal != -1) FreeSignal(1L << mySignal); /* close libraries */ if (GfxBase) _CloseLibrary(GfxBase); if (LayersBase) _CloseLibrary(LayersBase); if (IntuitionBase) _CloseLibrary(IntuitionBase); if (output) _Close(output); #asm moveq #0,d0 ;pick up return exit code move.l __savsp,sp ;get back original stack pointer rts ;and exit #endasm } /*********************************************/ int init() { long stat; /* global record of this task's ID */ myTask = _FindTask((char *) NULL); /* need intuitionbase to read mouse pos. & screen layer */ IntuitionBase = (struct IntuitionBase *) _OpenLibrary(i_libname + 1, 0L); if (IntuitionBase == NULL) { writes(i_libname); return 0; } /* need graphics since we do */ GfxBase = (struct GfxBase *) _OpenLibrary(g_libname + 1, 0L); if (GfxBase == NULL) { writes(g_libname); return 0; } /* layers for WhichLayer() */ LayersBase = (long) _OpenLibrary(l_libname + 1, 0L); if (LayersBase == NULL) { writes(l_libname); return 0; } /* signal from input event handler to main code */ mySignal = AllocSignal(-1L); if (mySignal == -1) { writes("!allocate a signal bit."); return 0; } /* a signal to this port will terminate us */ myPort = CreatePort(port_name + 1, 0L); if (myPort == NULL) { writes(port_name); return 0; } /* port to the input.device */ inpPort = CreatePort((char *) NULL, 0L); if (inpPort == NULL) { writes("^input.device port."); return 0; } /* need an i/o request */ inpReq = CreateStdIO(inpPort); if (inpReq == NULL) { writes("^input.device i/o request."); return 0; } /* open input.device */ stat = OpenDevice(i_devname + 1, 0L, inpReq, 0L); if (stat != 0) { writes(i_devname); return 0; } /* port to the console.device */ conPort = CreatePort((char *) NULL, 0L); if (!conPort) { writes("^console.device port."); return 0; } /* need an i/o request */ conReq = CreateStdIO(conPort); if (!conReq) { writes("^console.device i/o request."); return 0; } /* open console.device */ stat = OpenDevice(c_devname + 1, -1L, conReq, 0L); if (stat != 0) { writes(c_devname); return 0; } /* check for consolebase */ ConsoleBase = (struct ConsoleBase *) conReq->io_Device; if (!ConsoleBase) { writes("!find ConsoleBase."); return 0; } /* handler command stuff */ handler.is_Code = handlerCode; handler.is_Node.ln_Pri = 51; /* install new input event handler */ inpReq->io_Command = IND_ADDHANDLER; inpReq->io_Data = (APTR) &handler; stat = DoIO(inpReq); if (stat != 0) { writes("ADDHANDLER request failed."); return 0; } handlerIn = 1; /* function catchers */ oldRectFill = SetFunction(GfxBase, (long) lvoRectFill, myRectFill); if (oldRectFill == 0) { writes("!replace RectFill()"); return 0; } oldScrollRaster = SetFunction(GfxBase, (long) lvoScrollRaster, myScrollRaster); if (oldScrollRaster == 0) { writes("!replace ScrollRaster()"); return 0; } oldCloseWindow = SetFunction(IntuitionBase, (long) lvoCloseWindow, myCloseWindow); if (oldCloseWindow == 0) { writes("!replace CloseWindow()"); return 0; } return 1; } /*********************************************/ int jump(mode) int mode; { char ch; while (0 < msgp->alen--) { ch = *msgp->aptr++; if ((ch != ' ' && ch != '\t' && ch != '\n') == mode) return ch; } return 0; } /*********************************************/ int innum(base) int base; { int result, neg, ch; result = 0; ch = jump(1); if (!ch) return 0; neg = ch == '-'; if ((neg || ch == '+') && 0 < msgp->alen--) ch = *msgp->aptr++; while (1) { ch -= '0'; if (9 < ch) ch -= 7; /* was 'A'-'F' */ if (15 < ch) ch -= 32; /* was 'a'-'f' */ if (ch < 0 || base <= ch) { msgp->alen++; /* ungetc */ msgp->aptr--; break; } result = result * base + ch; if (msgp->alen-- <= 0) break; ch = *msgp->aptr++; } return neg ? -result : result; } /*********************************************/ usage() { writes("Usage: snipit [opts]"); writes("where opts can be any of:"); writes(" ? or h Help; this text"); writes(" q Quit; remove SnipIt from the system"); writes(" p \"prestring\" When pasting using Command-B key, insert"); writes(" \"prestring\" before each line. In quotes"); writes(" l 1 or 0 Lock layer (or don't) while snipping"); writes(" u +/-number Adjust cell x position in console windows"); writes(" v +/-number Adjust cell y position in console windows"); writes(" x +/-number Adjust cell x position in non-console windows"); writes(" y +/-number Adjust cell y position in non-console windows"); writes(" a hex-number Qualifier for Command-A key (default LEFT-AMIGA)"); writes(" b hex-number Qualifier for Command-B key (default LEFT-ALT)"); writes(""); writes("Defaults are: p\"> \" l0 u0 v0 x0 y0 a0040 b0010"); } /*********************************************/ int options() { char *cp; int temp, ch; msgp->done = msgp->huh = msgp->off = 0; do { /* locate a char after whitespace */ ch = jump(1); /* advance to 1st non-white */ if ('A' <= ch && ch <= 'Z') ch = ch - 'A' + 'a'; /* tolower */ /* act on char */ switch (ch) { case 0: break; case 'q': msgp->done = 1; return 0; /* die */ case 'p': cp = preString; ch = jump(1); /* delim char */ if (ch) { while (0 < msgp->alen-- && (*cp = *msgp->aptr++) != ch) { cp++; if (preString + PRE_SIZE <= cp) break; } } *cp = 0; break; case 'x': if (snip == WIN_SNIP) clearHi(); msgp->off = 1; win_offx += innum(10); break; case 'y': if (snip == WIN_SNIP) clearHi(); msgp->off = 1; win_offy += innum(10); break; case 'u': if (snip == CON_SNIP) clearHi(); msgp->off = 1; con_offx += innum(10); break; case 'v': if (snip == CON_SNIP) clearHi(); msgp->off = 1; con_offy += innum(10); break; case 'a': if (temp = innum(16)); cmd1 = temp; break; case 'b': if (temp = innum(16)); cmd2 = temp; break; case 'l': ch = jump(1); /* first char */ if (ch) lock_layer = ch == '1'; break; case 'w': ch = jump(1); /* first char */ if (ch) windows = ch == '1'; break; default: msgp->huh = 1; /* newline, too - end of string */ break; } } while (jump(0)); /* advance to whitespace */ if (msgp->off) { win_offx = win_offx < -32 ? -32 : 32 < win_offx ? 32 : win_offx; win_offy = win_offy < -32 ? -32 : 32 < win_offy ? 32 : win_offy; con_offx = con_offx < -32 ? -32 : 32 < con_offx ? 32 : con_offx; con_offy = con_offy < -32 ? -32 : 32 < con_offy ? 32 : con_offy; msgp->w_offx = win_offx; msgp->w_offy = win_offy; msgp->c_offx = con_offx; msgp->c_offy = con_offy; } return 1; /* i.e., keep running */ } /*********************************************/ outnum(n) int n; { char d; if (n < 0) { n = -n; _Write(output, "-", 1L); } if (n > 9) { d = n / 10 + '0'; _Write(output, &d, 1L); } d = n % 10 + '0'; _Write(output, &d, 1L); } /*********************************************/ currAdjust(type, x, y) char *type; int x, y; { _Write(output, type, 7L); _Write(output, " adjustment now: x=", 19L); outnum(x); _Write(output, ",y=", 3L); outnum(y); _Write(output, "\n", 1L); } /*********************************************/ checkStatus() { if (myMsg.huh) writes(huh_msg); else if (myMsg.done) writes("_ cancelled."); else if (myMsg.off) { currAdjust("Console", myMsg.c_offx, myMsg.c_offy); currAdjust("Window ", myMsg.w_offx, myMsg.w_offy); } } /*********************************************/ _main(alen, aptr) /* DOSBase and ExecBase opened already by crt0.o */ long alen; char *aptr; { static int pass; int keep_going; long sige, sigt; struct MsgPort *port, *rport; /* sever seglists */ do_detach(&alen, &aptr); myMsg.alen = alen; myMsg.aptr = aptr; /* help requested?? */ if (*aptr == '?' || *aptr == 'h') usage(); /* installed already? if so, pass arguments */ else if (port = FindPort(port_name + 1)) { if (alen <= 1) writes("_ already installed!"); else { myMsg.m.mn_ReplyPort = rport = CreatePort(NULL, 0L); if (!rport) writes("^a port"); else { PutMsg(port, &myMsg); _WaitPort(rport); /* wait for reply */ _GetMsg(rport); DeletePort(rport); /* check return stats */ checkStatus(); } } } /* install & deal with args */ else if (init()) { msgp = &myMsg; if (options() && !myMsg.huh) { writes("_ installed. \xA9 1988 - Scott Evernden"); running = 1; /* signals which mean something */ sige = 1L << mySignal; /* request for recognition */ sigt = 1L << myPort->mp_SigBit; /* options message */ /* process requests for handler code * while awaiting options signal */ keep_going = 1; while (keep_going) { if (Wait(sige | sigt) == sige) { buildEvents(); jobFlag = 0; /* lower active flag */ } else while (msgp = (struct MyMessage *) GetMsg(myPort)) { keep_going = options(); _ReplyMsg(msgp); } } } else { if (myMsg.huh) writes(huh_msg); writes("_ not installed."); } } running = 1; /* terminate */ Delay(10L); fini(); } SHAR_EOF cat << \SHAR_EOF > patch.c /* "Patch" fix SnipIt to use a different keymap */ /* 9/1/88 - Scott Evernden */ #include <stdio.h> #include <ctype.h> FILE *infile, *datafile; /* original keycode table starts like this... */ unsigned char match[] = { 0x40, 0x81, 0xAA, 0x83, 0x84, 0x85, 0x87, 0x2A, 0x89, 0x8A, 0x88, 0x8C, 0x38, 0x0B, 0x39, 0x3A, 0x0A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0 }; main() { long pos, ftell(); unsigned char *mp; int ch, i; /* gonna write into this file */ infile = fopen("SnipIt", "r+"); if (!infile) { puts("Can't open \"SnipIt\""); exit(0); } /8 need to read this one */ datafile = fopen("SnipIt.keys", "r"); if (!datafile) { puts("Can't open \"SnipIt.keys\""); exit(0); } /* locate original table */ mp = match; while (*mp && (ch = fgetc(infile)) != EOF) { if (ch != *mp) mp = match; else if (mp++ == match) pos = ftell(infile) - 1; } if (ch == EOF) { puts("Are you sure this is an original copy of \"SnipIt\"?"); fclose(infile); fclose(datafile); exit(0); } fputs("Patching keytable...", stdout); fseek(infile, pos, 0L); for (i = 32; i < 127; i++) fputc(innum() & 0xFF, infile); fclose(infile); fclose(datafile); puts("done"); } innum() { int result; int ch; do { ch = fgetc(datafile); } while (!isxdigit(ch)); if (ch == EOF) return 0; result = 0; do { ch -= '0'; if (9 < ch) ch -= 7; if (15 < ch) ch -= 32; result = result * 16 + ch; ch = fgetc(datafile); } while (isxdigit(ch)); return result; } SHAR_EOF cat << \SHAR_EOF > reco.c /* :ts=4 * * Amiga SnipIt 1.2 * (c) (opyright 1987,1988 - Scott Evernden - All Rights Reserved * * reco.c - recognize & construct char code input * */ #include "hs.h" char *_AllocMem(); /* ascii to keycode (this is a hack; is there a correct way to do this?) */ char table[] = { /* ! " # $ % & ' */ /* ( ) * + , - . / */ /* 0 1 2 3 4 5 6 7 */ /* 8 9 : ; < = > ? */ /* @ A B C D E F G */ /* H I J K L M N O */ /* P Q R S T U V W */ /* X Y Z [ \ ] ^ _ */ /* ` a b c d e f g */ /* h i j k l m n o */ /* p q r s t u v w */ /* x y z { | } ~ */ 0x40, 0x81, 0xAA, 0x83, 0x84, 0x85, 0x87, 0x2A, 0x89, 0x8A, 0x88, 0x8C, 0x38, 0x0B, 0x39, 0x3A, 0x0A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xA9, 0x29, 0xB8, 0x0C, 0xB9, 0xBA, 0x82, 0xA0, 0xB5, 0xB3, 0xA2, 0x92, 0xA3, 0xA4, 0xA5, 0x97, 0xA6, 0xA7, 0xA8, 0xB7, 0xB6, 0x98, 0x99, 0x90, 0x93, 0xA1, 0x94, 0x96, 0xB4, 0x91, 0xB2, 0x95, 0xB1, 0x1A, 0x0D, 0x1B, 0x86, 0x8B, 0x00, 0x20, 0x35, 0x33, 0x22, 0x12, 0x23, 0x24, 0x25, 0x17, 0x26, 0x27, 0x28, 0x37, 0x36, 0x18, 0x19, 0x10, 0x13, 0x21, 0x14, 0x16, 0x34, 0x11, 0x32, 0x15, 0x31, 0x9A, 0x8D, 0x9B, 0x80 }; static struct InputEvent event; char *evs, *evp; char preString[PRE_SIZE + 1] = "> "; /* a prestring */ int evslen; extern struct IOStdReq *inpReq; extern struct TextFont *capttf; extern struct BitMap captbm; extern int captx, capty; extern int charx, chary; extern int left, right; extern int cmd1, cmd2, jobFlag; /*********************************************/ /* cleanup, local to this module */ finiReco() { /* event string is allocated */ if (evs) _FreeMem(evs, (long) evslen); } /*********************************************/ /* entry to recognizer; generates keycode events from the capture bitmap */ buildEvents() { register char *cp; PLANEPTR p; int code; /* prepare request to input device */ inpReq->io_Command = IND_WRITEEVENT; inpReq->io_Flags = 0; inpReq->io_Length = sizeof (struct InputEvent); inpReq->io_Data = (APTR) &event; /* new snip-map? */ if (capttf) { /* new buffer for keycodes */ if (evs) _FreeMem(evs, (long) evslen); evslen = (captx / charx) * (capty / chary); evs = (char *) _AllocMem((long) evslen, 0L); if (evp = evs) buildCodes(); capttf = NULL; /* reset "newly-captured" indicator */ /* reco'ed, so drop the bitmap */ if (p = captbm.Planes[0]) { FreeRaster(p, (long) captx, (long) capty); captbm.Planes[0] = NULL; } } else if (evp = evs) { while (*evp != -1) { if (jobFlag & cmd2) { cp = preString; while (*cp) sendKey(*cp++); } do sendKey(code = *evp++); while (code != '\n' && *evp != -1); } } } /*********************************************/ /* inject a (fake) keyboard press/release into the input stream */ sendKey(code) int code; { /* convert to raw key */ code = code == '\n' ? 0x44 : table[code - 32]; /* build key down event */ event.ie_Class = IECLASS_RAWKEY; event.ie_Code = code & 0x7F; event.ie_Qualifier = IEQUALIFIER_RELATIVEMOUSE; if (code & 0x80) event.ie_Qualifier |= IEQUALIFIER_LSHIFT; event.ie_NextEvent = NULL; /* make it happen */ DoIO(inpReq); /* build key up event (req'd?) */ event.ie_Class = IECLASS_RAWKEY; event.ie_Code = (code & 0x7F) | IECODE_UP_PREFIX; event.ie_Qualifier = IEQUALIFIER_RELATIVEMOUSE; if (code & 0x80) event.ie_Qualifier |= IEQUALIFIER_LSHIFT; event.ie_NextEvent = NULL; /* make it happen */ DoIO(inpReq); } /*********************************************/ /* actually makes the keycodes */ buildCodes() { register int code, px, py, wid, lastx, lasty, spaces; char *cp; /* heuristics for text structure (i.e., newlines) */ px = left; py = 0; lastx = captx / charx - 1; lasty = capty / chary - 1; wid = lastx; while (py <= lasty) { /* prestring on cmd2 key */ if (jobFlag & cmd2) { cp = preString; while (*cp) sendKey(*cp++); /* don't record */ } /* on the last line? */ if (py == lasty) lastx = right; /* for each cell... */ while (px <= lastx) { /* recognize single character */ code = reco(px++, py); /* we're gonna count runs of spaces */ spaces = 0; while (code == ' ' && px <= wid) { spaces++; code = reco(px++, py); } /* send / record, if no spaces */ if (!spaces) sendKey(*evp++ = code); /* if end of line is all spaces, then regard as newline */ else if (code == ' ' && wid < px) sendKey(*evp++ = '\n'); /* if more text on line after snip area, then not a newline */ else if (py < lasty || px <= lastx + 1) { while (spaces--) sendKey(*evp++ = ' '); sendKey(*evp++ = code); } /* emit spaces */ else { spaces -= px - lastx - 2; while (spaces--) sendKey(*evp++ = ' '); } } /* next is leftside of next row down */ px = 0; py++; } *evp = -1; /* record terminator */ } /*********************************************/ /* return ascii code of character in capture bitmap at (x,y) */ int reco(x, y) int x, y; { register char *s, *d, *sp, *dp; register int hyt, i; /* recognize cell at (x,y) */ sp = (char *) capttf->tf_CharData; dp = (char *) captbm.Planes[0] + y * chary * captbm.BytesPerRow + x; for (i = 32; i < 128; sp++, i++) { s = sp; d = dp; hyt = capttf->tf_YSize; if (*s == *d) { do { if (--hyt == 0) return i; s += capttf->tf_Modulo; d += captbm.BytesPerRow; } while (*s == *d); } else if (*s == ~*d) { do { if (--hyt == 0) return i; s += capttf->tf_Modulo; d += captbm.BytesPerRow; } while (*s == ~*d); } } return '?'; /* unknown */ } SHAR_EOF cat << \SHAR_EOF > snipit.keys 40 81 AA 83 84 85 87 2A 89 8A 88 8C 38 0B 39 3A 0A 01 02 03 04 05 06 07 08 09 A9 29 B8 0C B9 BA 82 A0 B5 B3 A2 92 A3 A4 A5 97 A6 A7 A8 B7 B6 98 99 90 93 A1 94 96 B4 91 B2 95 B1 1A 0D 1B 86 8B 00 20 35 33 22 12 23 24 25 17 26 27 28 37 36 18 19 10 13 21 14 16 34 11 32 15 31 9A 8D 9B 80 SHAR_EOF cat << \SHAR_EOF > patch.doc KeyMap patcher: ============== The program "patch" will "fix" SnipIt to work with foreign, custom, and the Dvorak keymaps. This measure is a stopgap "bandaid" (i.e., hack) until a more appropriate handling of KeyMaps is employed by SnipIt. Make sure that (a copy of) "snipit" and a file named "snipit.keys" are in the 'current directory'. Simply incant: > patch and SnipIt will be modified according to the data in the "snipit.keys" file. The file "snipit.keys" has a format like the following (this example is the default- for the 'usa0' keymap): 40 81 AA 83 84 85 87 2A 89 8A 88 8C 38 0B 39 3A 0A 01 02 03 04 05 06 07 08 09 A9 29 B8 0C B9 BA 82 A0 B5 B3 A2 92 A3 A4 A5 97 A6 A7 A8 B7 B6 98 99 90 93 A1 94 96 B4 91 B2 95 B1 1A 0D 1B 86 8B 00 20 35 33 22 12 23 24 25 17 26 27 28 37 36 18 19 10 13 21 14 16 34 11 32 15 31 9A 8D 9B 80 It should be a list of 95 hexadecimal numbers, each corresponding to the ASCII codes 32-126 (95 codes- ' ' thru '~'). The hex number is the I.D. of the keyboard key (as revealed in the Appendix to the AmigaDOS Technical Manual and other sources). If the keyboard key must be "shifted" in order to achieve the corresponding ASCII code, then the hex keycode number is "OR"ed with an 0x80 (high bit on). The patch program simply searches the SnipIt program file looking for the original hardwired table, and then overwrites the 95 code values. Consequently, you need to run "patch" on the original copy of SnipIt. -scott SHAR_EOF cat << \SHAR_EOF > snipit.doc SnipIt 1.2 - Copyright (c) 1988 - Scott Evernden, All Rights Reserved What is SnipIt? ================ SnipIt is a CLI program which allows you to copy text directly from the Amiga screen in any window, and then paste it into any other place, as though you had typed that text at the keyboard. You mark the text you want to 'snip' using the mouse. You also use the mouse to 'paste' the last snipped text into the active window, requester, or anywhere. SnipIt is a program which installs itself into the input stream handling code of AmigaDOS. It waits for you to hold down the LEFT-AMIGA (or optionally another key) while using the mouse. Running the Program =================== This program will only run properly from the CLI. You start it like > snipit at which point, SnipIt will install itself, and print a message. You can control certain operations and modes of SnipIt when you first install it and later while it is running. You do this by typing "snipit" with 'option' letters and possible arguments. For example, you can tell SnipIt to stop running: > snipit q In other words, type "snipit" followed by a "q" for 'quit'. Other options to control SnipIt's behavior will be described below. Marking Text to be Copied ========================= To mark text to be copied, simply depress the LEFT-AMIGA key (by default), move the mouse pointer to a position in any window containing text and hold down the LEFT mouse button. While holding down the LEFT mouse button you move the mouse to the opposite end of the text area you want to copy and then release. As you do this, SnipIt will mark (hilight) both ends of the area you are designating. Once you have released the LEFT mouse button, SnipIt will fully highlight and 'snapshot' the text within the area you have marked out. Pasting the Copied Text ======================= You can deposit the text you copied by, again, holding down the LEFT-AMIGA key, and clicking the RIGHT mouse button. SnipIt will inject keystroke codes into the input stream, so you can paste text into any active window, requester, or anything else which is expecting keyboard input. You can paste copied text as many times as you want. SnipIt will un-hilight the selected area whenever any output occurs in the highlighted window. You can still paste the copied text, however, even though the highlighting has been removed. Limitations of This Version =========================== SnipIt can recognize any font in any height, only as long as that font is fixed width and 8 pixels wide. SnipIt in its current form cannot recognize text which is italicised, underlined, or is drawn in certain colors. In some unusual colored text cases, SnipIt will be 'blind' thinking it is seeing space characters, and you will get nothing but spaces while pasting. SnipIt can only recognize character codes between ASCII 32-127, so special characters (requiring the ALT key to generate) will not get recognized properly. If SnipIt cannot figure out a character, it will substitute a '?' (question mark) character. SnipIt appears to work properly with the ConMan replacement console handler by William Hawes. SnipIt also appears to work properly with the NEWCON: window of AmigaDOS 1.3. SnipIt may highlight areas in a peculiar fashion in windows having the GIMMEZEROZERO attribute (eg., AmigaBasic). This program will also co-operate with programs like SunMouse and others which can change window activation automatically. However, note that each character of any pasted text will arrive in whatever window the mouse is currently in. New Features of Version 1.2 =========================== Automatically runs in the background ------------------------------------ You no longer need to 'run' SnipIt- the program is now capable of detaching itself and running automatically in the background. Snips from both consoles and regular windows -------------------------------------------- SnipIt can now recognize text in plain old windows (not only just console windows anymore). So, applications like WPLibrary P-Edit and VT100 terminal programs can be 'snipped' from. Note that SnipIt assumes that text is being displayed in the window is some kind of cell array (like a terminal). It probably won't do what you want in programs like Deluxe Paint, and others which can place text anywhere in the window. Built in mini-help ------------------ SnipIt will give you a quick rundown of its options if you type: > snipit h or > snipit ? Prestring insertion while pasting --------------------------------- The program now provides an option to insert a short text string before each line of characters as it is pasted. This can be useful if you are 'snipping' text which you wish to 'quote'. You do this by depressing the LEFT-ALT key (by default), instead of the LEFT-AMIGA key while pasting. For example, if I snip, and then paste this paragraph using LEFT-ALT, I get: > The program now provides an option to insert a short text string > before each line of characters as it is pasted. This can be useful > if you are 'snipping' text which you wish to 'quote'. You do this > by depressing the LEFT-ALT key (by default), instead of the > LEFT-AMIGA key while pasting. For example, if I snip, and then > paste this paragraph using LEFT-ALT, I get: Note, a "> " (the default) string has been prepended to each pasted line. This string can be changed at any time by: > snipit p "the prestring: " where the text appears between quotes after a "p". Actually, you can use any delimiter, and not only quotes, like: > snipit p .the prestring: . Just repeat the initial character at the end. Your prestring must contain no more than 32 characters. Character cell location adjustments ----------------------------------- Sometimes, in non-console windows, the text may not be placed in positions that SnipIt can locate. SnipIt 1.2 now provides options that allow you to slightly adjust its idea of where characters are located in the window: > snipit x +2 y -1 will move the snip area in windows, right by 2 pixels and up by one. If you find that SnipIt is producing lots of ???????s while pasting, then you may need to use this option to adjust the cell area (highlighted area) slightly. For example, P-Edit currently requires: > snipit x -1 as text characters are draw one pixel higher than SnipIt would otherwise assume. Dave Wecker's VT100 currently requires: > snipit y -1 You can also correct the x and y cell positions in console windows using the 'u' and 'v' options: > snipit u -3 v +1 will move the snip area in consoles, left by 3 pixels, and down by one. For example, Eric Haberfellner's Handshake (VT100 emulator) currently needs: > snipit v +3 In most circumstances, you shouldn't need to use the 'u' and 'v' options to adjust for console windows. Improved recognition -------------------- SnipIt can now recognize highlighted and inverted characters- you no longer have to move that darn cursor away from your text. Freeze windows while snipping ----------------------------- If you type: > snipit l 1 ("l" for 'lock') Snipit 1.2 will freeze the window or console which you are snipping from. This can be useful if you are trying to 'snip' text in a window that would otherwise scroll. > snipit l 0 turns this option off. Re-assignable keyboard use -------------------------- Normally, you snip and paste using the LEFT-AMIGA key; you can paste with a prestring using the LEFT-ALT key while pasting. These key choices can be changed. You change the normal, or Command-A, key from the LEFT-AMIGA to another key by: > snipit a <hexcode> where the <hexcode> is from this table: LEFT-SHIFT .... 0001 RIGHT-SHIFT ... 0002 CONTROL ....... 0008 LEFT-ALT ...... 0010 <- default Command-B key RIGHT-ALT ..... 0020 LEFT-AMIGA .... 0040 <- default Command-A key RIGHT-AMIGA ... 0080 other values won't work. So, to use the CONTROL key instead, you: > snipit a 0008 (or just 8, you don't need the leading 0s). The Command-B key, normally the LEFT-ALT key, can be changed, for example, to the Right-Shift key: > snipit b 0002 Default settings ---------------- By default snipit acts as though you had done: > snipit p"> " l0 u0 v0 x0 y0 a0040 b0010 meaning: o (p) use "> " as the prestring when pasting with the Command-B key o (l) don't freeze the window being snipped from o (u, v) no adjustment to cell area when snipping from consoles o (x, y) no adjustment to cell area when snipping from windows o (a) use LEFT-AMIGA for Command-A operation- regular snips and pastes o (b) use LEFT-ALT for Command-B operation- insert prestring on pastes Bugs ==== I have not gone to any special effort to check if Windows or Screens are closed, or otherwise disappear, while the mouse is being used to highlight a text area. The system will likely Guru if this happens. SnipIt only works properly with the usa0 keymap (more below). Dvorak (usa2) will not, and certain non-usa keyboards/keymaps may not work properly with SnipIt. However, a 'patch' program is included to modify SnipIt to work with other keymaps. See the file "PATCH.DOC" for more information. Ideas for the Future ==================== In approximate order of importance to me: The next SnipIt will hopefully do a better job in dealing with KeyMaps. Currently, SnipIt uses a hardcoded table of keycodes for pasting character codes into the input stream. I'm not real happy with this, because it is not the best design. This will be fixed next. Recognize, as an option, ALL characters, even ones requiring the ALT key to generate (full 8-bit ASCII). An 'appending' snip. The next version of SnipIt will probably allow you to 'append' or add newly snipped material to the end of previously snipped text. This way, you could actually 'compose' a message by collecting text from different parts of one or several windows. The Command-B key is planned for this use while snipping. Send snipped text to a device or file instead of into the input stream. This way, you could direct snipped text into a PIPE:, for example. Use the clipboard- some day. Recognize text that isn't 8 pixels wide, is colored, underlined or italicised. Don't hold your breath on these. The SnipIt program acts like 2 different programs: 1. As the resident SnipIt program doing the real work. 2. As the user interface communicating options to the resident SnipIt. Currently, the resident SnipIt also carries the code used by the user interface portion. This is a mild waste of memory (less than 5K). A future version of SnipIt may release code sections not required for the resident portion, thereby reducing consumption of memory. ========================================================================== Comments and contributions to: ------------------------------ plink: SCOTT E bix: s_evernden cis: 73116,3451 uucp: {ames,rutgers}!harvard!m2c!applix!scott scott@applix.m2c.org Scott Evernden 9 Courtland St. Holliston, MA 01746 SHAR_EOF # End of shell archive exit 0 -- Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page Have five nice days.