/**************************************************** * vt100 emulator - window/keyboard support * * v2.7 870825 ACS - Provide an info/status window rather than using * req(). Better error handling. * v2.6 870227 DBW - bug fixes for all the stuff in v2.5 * v2.5 870214 DBW - more additions (see readme file) * v2.4 861214 DBW - lots of fixes/additions (see readme file) * v2.3 861101 DBW - minor bug fixes * v2.2 861012 DBW - more of the same * v2.1 860915 DBW - new features (see README) * 860823 DBW - Integrated and rewrote lots of code * v2.0 860809 DBW - Major rewrite * v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes * v1.0 860712 DBW - First version released * ****************************************************/ #include "vt100.h" /* keyboard definitions for toasc() */ static char keys[75] = { '`','1','2','3','4','5','6','7','8','9','0','-' , '=','\\', 0, '0','q','w','e','r','t','y','u','i','o' , 'p','[',']', 0, '1','2','3','a','s','d','f','g','h' , 'j','k','l',';','\'', 0, 0, '4','5','6', 0, 'z','x','c','v', 'b','n','m',44,'.','/', 0, '.','7','8','9',' ',8, '\t',13,13,27,127,0,0,0,'-' } ; /* For InfoMsg...may be changed by a NEWSIZE msg in vt100.c */ int reqminx, /* Min value for x in reqwindow (pixels) */ reqmaxx, /* Max value for x in reqwindow (pixels) */ reqmaxlen, /* Max # chars in reqwindow */ reqminy, /* Min value for y in reqwindow (scan lines) */ reqmaxy, /* Max value for y in reqwindow (scan lines) */ reqfudge; /* Clear space between border and start of 1st char */ int reqy; /* Current pixel location in reqwindow */ void ReqNewSize(), OpenReqWindow(); /*************************************************** * function to swap the use of backspace and delete ***************************************************/ void swap_bs_del() { if (p_bs_del) p_bs_del = 0; else p_bs_del = 1; keys[0x41] = p_bs_del ? 127 : 8; keys[0x46] = p_bs_del ? 8 : 127; } /************************************************* * function to get file name (via a requestor) *************************************************/ void req(prmpt,name,getinp) char *prmpt,*name; int getinp; { ULONG class; USHORT position, RemoveGadget(); unsigned int code, qual; int lprmpt, lname; struct IntuiMessage *Msg; if(reqwinup == 0) OpenReqWindow(); if(!getinp) { InfoMsg2Line(prmpt, name); return; } lprmpt = strlen(prmpt); lname = strlen(name); /* Don't use strings longer than what we've provided space for. */ if(lprmpt > (MAXGADSTR-1)) { emits("Prompt too long - truncated.\n"); lprmpt = MAXGADSTR-1; } if(lname > (MAXGADSTR-1)) { emits("Name too long - truncated.\n"); lname = MAXGADSTR-1; } if (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) { class = Msg->Class; ReplyMsg(Msg); if(class == REQCLEAR) numreqs = 0; if(class == NEWSIZE) ReqNewSize(reqwindow->Height, reqwindow->Width); } /* Make sure the prompt gets updated */ if (numreqs == 1 && strcmp(Prompt,prmpt) != 0) { EndRequest(&myrequest,reqwindow); do { Wait(1L << reqwindow->UserPort->mp_SigBit); while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) { class = Msg->Class; ReplyMsg(Msg); if(class == NEWSIZE) ReqNewSize(reqwindow->Height, reqwindow->Width); } } while (class != REQCLEAR); numreqs = 0; } /* copy in a prompt and a default */ strncpy(Prompt,prmpt,lprmpt); Prompt[lprmpt+1] = '\0'; strncpy(InpBuf,name,lname); InpBuf[lname+1] = '\0'; if (numreqs == 1) { /* If there is a requester... reuse it */ RefreshGadgets(&mystrgad, reqwindow, &myrequest); Delay(2L); } else { /* otherwise create it */ while(numreqs != 1) { if (Request(&myrequest, reqwindow) == 0) { emits("ERROR - CAN'T CREATE REQUESTOR FOR:\n"); emits(Prompt); emit('\n'); emits(InpBuf); emit('\n'); return; } else numreqs = 1; do { Wait(1L << reqwindow->UserPort->mp_SigBit); while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) { class = Msg->Class; ReplyMsg(Msg); if(class == REQCLEAR) numreqs = 0; if(class == NEWSIZE) ReqNewSize(reqwindow->Height, reqwindow->Width); } } while (class != REQSET); } /* end while numreqs != 0 */ } /* end else */ /* if we don't want input, we're done */ if (getinp == 0 || numreqs == 0) return; if((reqwindow->Flags & WINDOWACTIVE) != WINDOWACTIVE) { WindowToFront(reqwindow); ActivateWindow(reqwindow); do { Wait(1L << reqwindow->UserPort->mp_SigBit); while(Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) { class = Msg->Class; ReplyMsg(Msg); if(class == NEWSIZE) ReqNewSize(reqwindow->Height, reqwindow->Width); } } while (class != ACTIVEWINDOW); } /* here is where we pre-select the gadget */ if (!ActivateGadget(&mystrgad,reqwindow,&myrequest)) { /* wait for his/her hands to get off the keyboard (Amiga-key) */ Delay(20L); while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) { ReplyMsg(Msg); if(class == NEWSIZE) ReqNewSize(reqwindow->Height, reqwindow->Width); } /* try once more before giving up... */ ActivateGadget(&mystrgad,reqwindow,&myrequest); } /* wait for input to show up */ while (1) { if ((NewMessage = (struct IntuiMessage *) GetMsg(reqwindow->UserPort)) == FALSE) { Wait(1L<UserPort->mp_SigBit); continue; } class = NewMessage->Class; ReplyMsg(NewMessage); /* the requestor got terminated... yea!! */ if (class == REQCLEAR) break; if(class == NEWSIZE) ReqNewSize(reqwindow->Height, reqwindow->Width); /* maybe this is a menu item to handle */ /* if (class == MENUPICK) handle_menupick(class,code); */ } /* all done, so return the result */ numreqs = 0; strcpy(name,InpBuf); } /************************************************* * function to print a string *************************************************/ void emits(string) char string[]; { int i; char c; i=0; while (string[i] != 0) { c=string[i]; if (c == 10) emit(13); emit(c); i += 1; } } /************************************************* * function to output ascii chars to window *************************************************/ void emit(c) char c; { static char wrap_flag = 0; /* are we at column 80? */ c &= 0x7F; switch( c ) { case '\t': x += 64 - ((x-MINX) % 64); break; case 10: /* lf */ y += 8; break; case 13: /* cr */ x = MINX; break; case 8: /* backspace */ x -= 8; if (x < MINX) x = MINX; break; case 12: /* page */ x = MINX; y = MINY; SetAPen(mywindow->RPort,0L); RectFill(mywindow->RPort,(long)MINX, (long)(MINY-7),(long)(MAXX+7),(long)(MAXY+1)); SetAPen(mywindow->RPort,1L); break; case 7: /* bell */ if (p_volume == 0) DisplayBeep(NULL); else { BeginIO(&Audio_Request); WaitIO(&Audio_Request); } break; default: if (c < ' ' || c > '~') break; if (p_wrap && wrap_flag && x >= MAXX) { x = MINX; y += 8; if (y > MAXY) { y = MAXY; ScrollRaster(mywindow->RPort,0L,8L,(long)MINX, (long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1)); } } Move(mywindow->RPort,(long)x,(long)y); if (curmode&FSF_BOLD) { if (p_depth > 1) { SetAPen(mywindow->RPort,(long)(2+(1^p_screen))); SetSoftStyle(mywindow->RPort,(long)curmode,253L); } else SetSoftStyle(mywindow->RPort,(long)curmode,255L); } else SetSoftStyle(mywindow->RPort,(long)curmode,255L); if (curmode&FSF_REVERSE) { SetDrMd(mywindow->RPort,(long)(JAM2+INVERSVID)); Text(mywindow->RPort,&c,1L); SetDrMd(mywindow->RPort,(long)JAM2); } else Text(mywindow->RPort,&c,1L); if (curmode&FSF_BOLD) SetAPen(mywindow->RPort,1L); x += 8; } /* end of switch */ if (y > MAXY) { y = MAXY; x = MINX; ScrollRaster(mywindow->RPort,0L,8L,(long)MINX, (long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1)); } if (x > MAXX) { wrap_flag = 1; x = MAXX; } else wrap_flag = 0; } /************************************************* * function to output ascii chars to window (batched) *************************************************/ void emitbatch(la,lookahead) int la; char *lookahead; { int i; Move(mywindow->RPort,(long)x,(long)y); i = x / 8; if (i+la >= maxcol) { if (p_wrap == 0) la = maxcol - i; else { lookahead[la] = 0; emits(lookahead); return; } } if (curmode&FSF_BOLD) { if (p_depth > 1) { SetAPen(mywindow->RPort,(long)(2+(1^p_screen))); SetSoftStyle(mywindow->RPort,(long)curmode,253L); } else SetSoftStyle(mywindow->RPort,(long)curmode,255L); } else SetSoftStyle(mywindow->RPort,(long)curmode,255L); if (curmode&FSF_REVERSE) { SetDrMd(mywindow->RPort,(long)(JAM2+INVERSVID)); Text(mywindow->RPort,lookahead,(long)la); SetDrMd(mywindow->RPort,(long)JAM2); } else Text(mywindow->RPort,lookahead,(long)la); if (curmode&FSF_BOLD) SetAPen(mywindow->RPort,1L); x += (8 * la); } /****************************** * Manipulate cursor ******************************/ void cursorflip() { SetDrMd(mywindow->RPort,(long)COMPLEMENT); SetAPen(mywindow->RPort,3L); RectFill(mywindow->RPort, (long)(x-1),(long)(y-6),(long)(x+8),(long)(y+1)); SetAPen(mywindow->RPort,1L); SetDrMd(mywindow->RPort,(long)JAM2); } /************************************************ * function to take raw key data and convert it * into ascii chars **************************************************/ int toasc(code,qual,local) unsigned int code,qual; int local; { unsigned int ctrl,shift,capsl,amiga,alt; char c = 0, keypad = 0; char *ptr; ctrl = qual & IEQUALIFIER_CONTROL; capsl = qual & IEQUALIFIER_CAPSLOCK; amiga = qual & (IEQUALIFIER_LCOMMAND | IEQUALIFIER_RCOMMAND); shift = qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT); alt = qual & (IEQUALIFIER_LALT | IEQUALIFIER_RALT); switch ( code ) { case 98: case 226: case 99: case 227: case 96: case 97: case 224: case 225: case 100: case 101: case 228: case 229: case 102: case 103: case 230: case 231: c = 0; break; /* ctrl, shift, capsl, amiga, or alt */ case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: c = 0; if (shift) ptr = p_F[code - 0x50]; else ptr = p_f[code - 0x50]; if (!script_on && *ptr == p_keyscript) script_start(++ptr); else sendstring(ptr); break; case 0x0f: c = (p_keyapp) ? 'p' : '0'; keypad = TRUE; break; case 0x1d: c = (p_keyapp) ? 'q' : '1'; keypad = TRUE; break; case 0x1e: c = (p_keyapp) ? 'r' : '2'; keypad = TRUE; break; case 0x1f: c = (p_keyapp) ? 's' : '3'; keypad = TRUE; break; case 0x2d: c = (p_keyapp) ? 't' : '4'; keypad = TRUE; break; case 0x2e: c = (p_keyapp) ? 'u' : '5'; keypad = TRUE; break; case 0x2f: c = (p_keyapp) ? 'v' : '6'; keypad = TRUE; break; case 0x3d: c = (p_keyapp) ? 'w' : '7'; keypad = TRUE; break; case 0x3e: c = (p_keyapp) ? 'x' : '8'; keypad = TRUE; break; case 0x3f: c = (p_keyapp) ? 'y' : '9'; keypad = TRUE; break; case 0x43: c = (p_keyapp) ? 'M' : 13 ; keypad = TRUE; break; case 0x4a: c = (p_keyapp) ? 'l' : '-'; keypad = TRUE; break; case 0x5f: sendstring("\033Om") ;break; case 0x3c: c = (p_keyapp) ? 'n' : '.'; keypad = TRUE; break; case 0x4c: case 0x4d: case 0x4e: case 0x4f: sendchar(27); /* cursor keys */ if (p_curapp) sendchar('O'); else sendchar('['); sendchar(code - 11); break; default: if (code < 75) c = keys[code]; else c = 0; } if (keypad) { if (p_keyapp) sendstring("\033O"); sendchar(c); return(0); } /* add modifiers to the keys */ if (c != 0) { if (shift) { if ((c <= 'z') && (c >= 'a')) c -= 32; else switch( c ) { case '[': c = '{'; break; case ']': c = '}'; break; case '\\': c = '|'; break; case '\'': c = '"'; break; case ';': c = ':'; break; case '/': c = '?'; break; case '.': c = '>'; break; case ',': c = '<'; break; case '`': c = '~'; break; case '=': c = '+'; break; case '-': c = '_'; break; case '1': c = '!'; break; case '2': c = '@'; break; case '3': c = '#'; break; case '4': c = '$'; break; case '5': c = '%'; break; case '6': c = '^'; break; case '7': c = '&'; break; case '8': c = '*'; break; case '9': c = '('; break; case '0': c = ')'; break; default: break; } } else if (capsl && (c <= 'z') && (c >= 'a')) c -= 32; } if (ctrl) { if (c > '`' && c <= 127) c -= 96; else if (c > '@' && c <= '_') c -= 64; else if (c == '6') c = 30; else if (c == '-' || c == '?') c = 31; } if (ctrl && (c == '@' || c == '2' || c == ' ')) { if (!local) sendchar(alt?128:0); c = 0; } else if (c != 0 && (!local)) sendchar(alt?c+128:c); return((int)c); } void KillReq() { struct IntuiMessage *Msg; ULONG class; if(numreqs != 0) { EndRequest(&myrequest,reqwindow); do { Wait(1L << reqwindow->UserPort->mp_SigBit); while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) { class = Msg->Class; ReplyMsg(Msg); } } while (class != REQCLEAR); numreqs = 0; } if(reqwinup) { /* First, clear out all pending messages */ while (Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) { class = Msg->Class; ReplyMsg(Msg); } NewReqWindow.LeftEdge = reqwindow->LeftEdge; /* Remember ... */ NewReqWindow.TopEdge = reqwindow->TopEdge; /* ...where... */ NewReqWindow.Width = reqwindow->Width; /* ...the user... */ NewReqWindow.Height = reqwindow->Height; /* ...put it. */ CloseWindow(reqwindow); /* Now we can close the window */ reqwinup = 0; } } void InfoMsg2Line(header, msg) char *header, *msg; { ScrollInfoMsg(1); InfoMsgNoScroll(header); ScrollInfoMsg(1); InfoMsgNoScroll(msg); ScrollInfoMsg(1); } void InfoMsg1Line(msg) char *msg; { ScrollInfoMsg(1); InfoMsgNoScroll(msg); ScrollInfoMsg(1); } /* Output the specified data to the "info" window */ void ScrollInfoMsg(lines) int lines; { /* ULONG class; struct IntuiMessage *Msg; */ int pixels = lines << 3; if(!reqwinup) OpenReqWindow(); /* if(Msg=(struct IntuiMessage *)GetMsg(reqwindow->UserPort)) { class = Msg->Class; ReplyMsg(Msg); if(class == NEWSIZE) ReqNewSize(reqwindow->Height, reqwindow->Width); } */ if ( (reqy += pixels) > reqmaxy) { reqy = reqmaxy; if(pixels > 0) ScrollRaster(reqwindow->RPort, 0L, (LONG)pixels, (LONG)reqminx, (LONG)reqminy, (LONG)(reqmaxx+7), (LONG)(reqmaxy+7)); /* Was: (LONG)(wp->Width - wp->BorderRight), (LONG)(wp->Height - wp->BorderBottom)); */ } } void InfoMsgNoScroll(msg) char *msg; { LONG msglen = strlen(msg); if(msglen > reqmaxlen) msglen = reqmaxlen; ScrollInfoMsg(0); /* Ensure that the msg willbe visible */ /* Position the pen at the baseline of the character (7 scan lines ** into it). */ Move(reqwindow->RPort, (LONG)reqminx, (LONG)(reqy+6)); Text(reqwindow->RPort, msg, msglen); } void ReqNewSize(height, width) SHORT height, width; { register struct Window *wp = reqwindow; int oldmaxy; /* Compute min and max for x and y coordinates. Note that for y the ** value is for the *top* of the character, not the baseline. Text() ** uses a baseline value and so it must be adjusted prior to the call ** (characters are assumed to occupy an 8x8 matrix with the baseline at ** 7). When computing the max values, calculate them so that we will ** sufficient room for an entire character. */ oldmaxy = reqmaxy; reqminy = wp->BorderTop + reqfudge; reqmaxy = (((height - reqminy - wp->BorderBottom) >> 3) << 3) + (reqminy-8); reqminx = wp->BorderLeft + reqfudge; reqmaxx = (((width - reqminx - wp->BorderRight) >> 3) << 3) + (reqminx-8); reqmaxlen = (reqmaxx+7) / 8; if(oldmaxy > reqmaxy) { /* Clean up the bottom of the window */ int temp = height - wp->BorderBottom - reqmaxy; ScrollRaster(wp->RPort, 0L, (LONG)temp, (LONG)reqminx, (LONG)reqmaxy, (LONG)(width - wp->BorderRight), (LONG)(height - wp->BorderBottom)); } } void OpenReqWindow() { struct IntuiMessage *Msg; ULONG class; void ReqNewSize(); reqwindow = OpenWindow(&NewReqWindow); do { Wait(1L << reqwindow->UserPort->mp_SigBit); while(Msg = (struct IntuiMessage *)GetMsg(reqwindow->UserPort)) { class = Msg->Class; ReplyMsg(Msg); } } while (class != ACTIVEWINDOW); reqfudge = 0; /* Leave 0 pixels/scan lines between border and char */ ReqNewSize(reqwindow->Height, reqwindow->Width); reqy = reqminy; /* Top of character set by ReqNewSize() */ reqwinup = 1; }