/* * Windows H19 Terminal Emulator Function Support Module * * Written by William S. Hall * 3665 Benton Street, #66 * Santa Clara, CA 95051 */ #define NOKANJI #define NOATOM #define NOMINMAX #include #include #include #include #include #include "winasc.h" #include "winh19.h" #include "win19d.h" #if defined(KERMIT) #include "winkpf.h" extern krmState; #endif /* ansi emulation manifests */ #define MAX_PARAM_LIST 32 #define BEGIN_ANSI_COMMAND 10 #define ANSI_INDIGIT 11 #define ANSI_ENDDIGIT 12 #define ANSI_MODE 13 #define ANSI_SET 14 #define ANSI_MODE_INDIGIT 15 #define ANSI_SET_INDIGIT 16 #define ANSI_MODE_ENDDIGIT 17 #define ANSI_SET_ENDDIGIT 18 /* ansi emulation local parameters */ static int ParamListIndex; static int ANSIParam; static int ANSIParamList[MAX_PARAM_LIST + 1]; static int NEAR InDigitTransition(BYTE ch, unsigned instate, unsigned endstate, void (NEAR *action)(BYTE)); static void NEAR PositionRow(BYTE y); static void NEAR PositionCol(BYTE x); static void NEAR SwitchActiveWindow(HWND hWnd); static void NEAR ProcessESCCommand(BYTE ch); static void NEAR MoveStatWindow(short height); static void NEAR ProcessBaudChange(int); static void NEAR IdentifyTerm(void); static void NEAR ReportCursorPosition(short line, short col); static BOOL NEAR DoKeyTranslation(unsigned message, WORD *wparam); static void NEAR DoANSICommand(int state, BYTE ch); static void NEAR ANSISetCommand(BYTE ch); static void NEAR ANSIModeCommand(BYTE ch); static void NEAR PlaceInList(int val); static void NEAR ANSICommand(BYTE ch); static void NEAR DoHeathCommand(int state, BYTE ch); static BOOL NEAR InNumpadSet(unsigned val); static WORD NEAR EditToNumpadShort(unsigned val); static WORD NEAR NumpadToEdit(unsigned val); static WORD NEAR EditToNumpadLong(unsigned val); /* special key handler when off-line */ void NEAR H19LocalKeyDown(WORD keycode) { switch (keycode) { case VK_UP: SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORUP,1L); break; case VK_DOWN: SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORDOWN,1L); break; case VK_RIGHT: SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORRIGHT,1L); break; case VK_LEFT: SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORLEFT,1L); break; case VK_HOME: CD.ICToggle = (CD.ICToggle ? FALSE : TRUE); break; case VK_END: SendMessage(hWndActive, WH19_COMMAND, H19_INSERTLINE,1L); break; case VK_PRIOR: SendMessage(hWndActive, WH19_COMMAND,H19_DELETECHAR,1L); break; case VK_NEXT: SendMessage(hWndActive, WH19_COMMAND, H19_DELETELINE,1L); break; case VK_CLEAR: SwitchActiveWindow(TW.hWnd); SendMessage(hWndActive, WH19_COMMAND, H19_CURSORHOME,0L); break; case VK_F6: if (GetKeyState(VK_SHIFT) & 0x8000) SendMessage(hWndActive, WH19_COMMAND, H19_CLRSCREEN,0L); else SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFSCREEN,0L); break; } } /* communications processor */ BOOL NEAR DoMessage() { MSG msg; if (PeekMessage((LPMSG)&msg,NULL,0,0,PM_REMOVE)) { if (msg.message == WM_QUIT) exit((int)msg.wParam); if (TranslateAccelerator(MW.hWnd,hAccel,(LPMSG)&msg) == 0) { if (DoKeyTranslation(msg.message, &msg.wParam)) TranslateMessage((LPMSG)&msg); DispatchMessage((LPMSG)&msg); } return TRUE; } return FALSE; } /* return TRUE if key is to be translated */ static BOOL NEAR DoKeyTranslation(unsigned message, WORD *wparam) { register unsigned shiftstate, numstate; int retval = TRUE; if ((message == WM_KEYDOWN) || (message == WM_KEYUP)) { if (*wparam == VK_CANCEL) return FALSE; if (*wparam == VK_BACK) { if (GetKeyState(VK_CONTROL) & 0x8000) return FALSE; return TRUE; } numstate = GetKeyState(VK_NUMLOCK); shiftstate = (GetKeyState(VK_SHIFT) & 0x8000) >> 15; if (CD.ShiftedKeypad) { if (numstate | shiftstate) { if (InNumpadSet(*wparam)) *wparam = NumpadToEdit(*wparam); else *wparam = EditToNumpadLong(*wparam); } else *wparam = EditToNumpadShort(*wparam); } else { if (!(numstate | shiftstate)) *wparam = EditToNumpadLong(*wparam); else *wparam = EditToNumpadShort(*wparam); } if (CD.AltKeypad) if (InNumpadSet(*wparam)) retval = FALSE; } return retval; } /* support modules for key translation */ static BOOL NEAR InNumpadSet(unsigned val) { return(((val >= VK_NUMPAD0) && (val <= VK_NUMPAD9)) || (val == VK_DECIMAL)); } static WORD NEAR NumpadToEdit(unsigned val) { switch (val) { case VK_NUMPAD1: val = VK_END; break; case VK_NUMPAD2: val = VK_DOWN; break; case VK_NUMPAD3: val = VK_NEXT; break; case VK_NUMPAD4: val = VK_LEFT; break; case VK_NUMPAD5: val = VK_CLEAR; break; case VK_NUMPAD6: val = VK_RIGHT; break; case VK_NUMPAD7: val = VK_HOME; break; case VK_NUMPAD8: val = VK_UP; break; case VK_NUMPAD9: val = VK_PRIOR; break; } return val; } static WORD NEAR EditToNumpadShort(unsigned val) { switch (val) { case VK_DELETE: val = VK_DECIMAL; break; case VK_INSERT: val = VK_NUMPAD0; break; } return val; } static WORD NEAR EditToNumpadLong(unsigned val) { switch (val) { case VK_DELETE: val = VK_DECIMAL; break; case VK_INSERT: val = VK_NUMPAD0; break; case VK_END: val = VK_NUMPAD1; break; case VK_DOWN: val = VK_NUMPAD2; break; case VK_NEXT: val = VK_NUMPAD3; break; case VK_LEFT: val = VK_NUMPAD4; break; case VK_CLEAR: val = VK_NUMPAD5; break; case VK_RIGHT: val = VK_NUMPAD6; break; case VK_HOME: val = VK_NUMPAD7; break; case VK_UP: val = VK_NUMPAD8; break; case VK_PRIOR: val = VK_NUMPAD9; break; } return val; } /* process string from comm port */ int NEAR H19StringInput(BYTE *str, short len) { register BYTE *ptr; register short ctr; short state; BYTE ch; int numrem; while (len) { if (state = CD.CommandState) { ch = *str & 0x7f; if (CD.ANSIMode) DoANSICommand(state, ch); else DoHeathCommand(state, ch); str++; len -= 1; } else { ctr = 0; ptr = str; while (len) { if ((*ptr &= 0x7f) != ESC) { ctr += 1; ptr++; len -= 1; } else { ptr++; len -= 1; CD.CommandState = ESC_COMMAND; break; } } if (ctr) { numrem = (int)SendMessage(hWndActive,WH19_STRINGINPUT,(WORD)ctr, (LONG)(LPSTR)str); if (numrem) return(len + numrem); } str = ptr; } } return (len); } /* start ansi processing */ static void NEAR DoANSICommand(int state, BYTE ch) { register int newstate; if (ch == CAN) newstate = NO_COMMAND; else if (ch == ESC) newstate = ESC_COMMAND; else { switch(state) { case ESC_COMMAND: switch (ch) { case '[': ParamListIndex = 0; ANSIParam = 0; ANSIParamList[0] = 0; newstate = BEGIN_ANSI_COMMAND; break; case 'M': SendMessage(hWndActive, WH19_COMMAND, H19_REVERSELINEFEED,0L); newstate = NO_COMMAND; break; case '=' : /* enter alternate keypad */ CD.AltKeypad = TRUE; newstate = NO_COMMAND; break; case '>' : /* exit alternate keypad */ CD.AltKeypad = FALSE; newstate = NO_COMMAND; break; default: newstate = NO_COMMAND; break; } break; case BEGIN_ANSI_COMMAND: switch(ch) { case '?': newstate = ANSI_MODE; break; case '>': newstate = ANSI_SET; break; default: newstate = InDigitTransition(ch, ANSI_INDIGIT, ANSI_ENDDIGIT, ANSICommand); break; } break; case ANSI_INDIGIT: case ANSI_ENDDIGIT: newstate = InDigitTransition(ch, ANSI_INDIGIT, ANSI_ENDDIGIT, ANSICommand); break; case ANSI_MODE: case ANSI_MODE_INDIGIT: case ANSI_MODE_ENDDIGIT: newstate = InDigitTransition(ch, ANSI_MODE_INDIGIT, ANSI_MODE_ENDDIGIT,ANSIModeCommand); break; case ANSI_SET: case ANSI_SET_INDIGIT: case ANSI_SET_ENDDIGIT: newstate = InDigitTransition(ch, ANSI_SET_INDIGIT, ANSI_SET_ENDDIGIT,ANSISetCommand); break; } } CD.CommandState = newstate; } /* support modules for ansi emulation */ static int NEAR InDigitTransition(BYTE ch, unsigned instate, unsigned endstate, void (NEAR *action)(BYTE)) { register int state; if (isdigit(ch)) { ANSIParam = 10 * ANSIParam + ch - '0'; state = instate; } else if (ch == ';') { PlaceInList(ANSIParam); state = endstate; } else { PlaceInList(ANSIParam); (*action)(ch); state = NO_COMMAND; } return state; } static void NEAR ANSISetCommand(BYTE ch) { register int i; if (ch == 'h') for (i = 0; i < ParamListIndex; i++) ProcessSetCommand(ANSIParamList[i]); else if (ch == 'l') for (i = 0; i < ParamListIndex; i++) ProcessResetCommand(ANSIParamList[i]); } static void NEAR ANSIModeCommand(BYTE ch) { register int i; if (ch == 'h') { for (i = 0; i < ParamListIndex; i++) { switch (ANSIParamList[i]) { case 2: CD.ANSIMode = FALSE; return; case 7: CD.WrapAround = TRUE; break; } } } else if (ch == 'l') { for (i = 0; i < ParamListIndex; i++) { switch (ANSIParamList[i]) { case 7: CD.WrapAround = FALSE; break; } } } } static void NEAR PlaceInList(int val) { if (ParamListIndex < MAX_PARAM_LIST) ANSIParamList[ParamListIndex++] = val; ANSIParam = 0; } static void NEAR ANSICommand(BYTE ch) { register int val1 = ANSIParamList[0]; register int val2 = ANSIParamList[1]; int i; switch(ch) { case 'A' : /* move cursor up */ if (val1 == 0) val1 = 1; SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORUP,(LONG)val1); break; case 'B' : /* move cursor down */ if (val1 == 0) val1 = 1; SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORDOWN,(LONG)val1); break; case 'C' : if (val1 == 0) val1 = 1; SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORRIGHT,(LONG)val1); break; case 'D' : if (val1 == 0) val1 = 1; SendMessage(hWndActive,WH19_COMMAND,H19_MOVECURSORLEFT,(LONG)val1); break; case 'f': case 'H': switch(ParamListIndex) { case 0: PositionRow(0); PositionCol(0); break; case 1: if (val1 == 0) val1 = 1; PositionRow(LOBYTE(val1 - 1)); PositionCol(0); break; default: if (val1 == 0) val1 = 1; if (val2 == 0) val2 = 1; PositionRow(LOBYTE(val1 - 1)); PositionCol(LOBYTE(val2 - 1)); break; } break; case 'J': if (ParamListIndex == 0) SendMessage(hWndActive,WH19_COMMAND,H19_CLRTOENDOFSCREEN,0L); else { switch(val1) { case 0: SendMessage(hWndActive,WH19_COMMAND,H19_CLRTOENDOFSCREEN,0L); break; case 1: SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOTOPOFSCREEN,0L); break; case 2: SendMessage(hWndActive, WH19_COMMAND, H19_CLRSCREEN,0L); break; } } break; case 'K': if (ParamListIndex == 0) SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFLINE,0L); else { switch(val1) { case 0: SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFLINE,0L); break; case 1: SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOSTARTOFLINE,0L); break; case 2: SendMessage(hWndActive, WH19_COMMAND, H19_ERASELINE,0L); break; } } break; case 'L' : /* insert line */ if (val1 == 0) val1 = 1; SendMessage(hWndActive, WH19_COMMAND, H19_INSERTLINE,(LONG)val1); break; case 'M' : /* delete line */ if (val1 == 0) val1 = 1; SendMessage(hWndActive, WH19_COMMAND, H19_DELETELINE,(LONG)val1); break; case 'P' : /* delete char */ if (val1 == 0) val1 = 1; SendMessage(hWndActive, WH19_COMMAND,H19_DELETECHAR,(LONG)val1); break; case 'h' : for (i = 0; i < ParamListIndex; i++) { switch (ANSIParamList[i]) { case 2: CD.KeyboardDisabled = TRUE; break; case 4: CD.ICToggle = TRUE; break; case 20: CD.CRonLF = TRUE; break; } } break; case 'l' : for (i = 0; i < ParamListIndex; i++) { switch (ANSIParamList[i]) { case 2: CD.KeyboardDisabled = FALSE; break; case 4: CD.ICToggle = FALSE; break; case 20: CD.CRonLF = FALSE; break; } } break; case 'm': for (i = 0; i < ParamListIndex; i++) { switch (ANSIParamList[i]) { case 0: CD.InverseVideo = FALSE; CD.CharAttribute = 0; break; case 7: CD.InverseVideo = TRUE; CD.CharAttribute = 0x80; break; case 10: CD.GraphicsMode = TRUE; break; case 11: CD.GraphicsMode = FALSE; break; } } break; case 'n' : switch(val1) { case 6: if (CD.LineState == IDM_ONLINE) { short currow, curcol; SendMessage(hWndActive, WH19_CURSORPOSITION, H19_GETCURSOR,MAKELONG(&currow, &curcol)); ReportCursorPosition(currow,curcol); } } break; case 'p': SendScreen(&TW); break; case 'q': SendStatusLine(&SW); break; case 'r': ProcessBaudChange(val1 - 1); break; case 's' : SendMessage(hWndActive, WH19_CURSORPOSITION,H19_SAVECURSOR, 0L); break; case 'u' : PositionRow((BYTE)CD.CurSaveRow); PositionCol((BYTE)CD.CurSaveCol); break; case 'z': ResetTerminal(); break; } } /* Heath emulation modules */ static void NEAR DoHeathCommand(int state, BYTE ch) { if (ch == CAN) CD.CommandState = NO_COMMAND; else if (ch == ESC) CD.CommandState = ESC_COMMAND; else { switch(state) { case ESC_COMMAND: ProcessESCCommand(ch); break; case YPOS_COMMAND: PositionRow((BYTE)(ch - SP)); break; case XPOS_COMMAND: PositionCol((BYTE)(ch - SP)); break; case SET_COMMAND: ProcessSetCommand((int)(ch - '0')); break; case RESET_COMMAND: ProcessResetCommand((int)(ch - '0')); break; case SETBAUD_COMMAND: ProcessBaudChange((int)(ch - 'A')); break; } } } static void NEAR PositionRow(BYTE y) { register short maxlines = TW.MaxLines; CD.CommandState = XPOS_COMMAND; if ((y >= 0) && (y < (BYTE)maxlines)) { SwitchActiveWindow(TW.hWnd); SendMessage(TW.hWnd,WH19_COMMAND,H19_POSITIONCURSORROW,(LONG)y); } else if (y == (BYTE)maxlines) if (CD.StatOpen) SwitchActiveWindow(SW.hWnd); } static void NEAR PositionCol(BYTE x) { register short cols = TW.MaxCols; CD.CommandState = NO_COMMAND; if ((x < 0) || (x >= (BYTE)cols)) x = (BYTE)(cols - 1); SendMessage(hWndActive, WH19_COMMAND, H19_POSITIONCURSORCOL, (LONG)x); } static void NEAR SwitchActiveWindow(HWND hWnd) { if (hWndActive != hWnd) { SendMessage(hWndActive, WH19_CARETFUNCTION, H19_DESTROYCARET, (LONG)CD.OwnCaret); hWndActive = hWnd; SendMessage(hWndActive, WH19_CARETFUNCTION, H19_CREATECARET, (LONG)CD.OwnCaret); } } void ProcessSetCommand(int ch) { CD.CommandState = NO_COMMAND; switch(ch) { case 1 : /* enable status line */ if (!CD.StatOpen) { CD.StatOpen = TRUE; memset(SW.pVidBuffer, SP, TW.MaxCols); MoveStatWindow(MW.Height); InvalidateRect(SW.hWnd, (LPRECT)NULL, TRUE); UpdateWindow(SW.hWnd); if (hWndActive == SW.hWnd) SendMessage(hWndActive,WH19_CARETFUNCTION,H19_SHOWCARET,0L); SendMessage(hWndActive, WH19_COMMAND, H19_ADJUSTWINDOW,0L); } break; case 2 : /* no key click */ CD.KeyClick = FALSE; break; case 3 : /* hold screen mode */ CD.HoldScreen = TRUE; break; case 4 : /* block cursor */ if (!CD.BlockCursor) { CD.BlockCursor = TRUE; SendMessage(hWndActive,WH19_CARETFUNCTION,H19_DESTROYCARET, (LONG)CD.OwnCaret); SendMessage(hWndActive,WH19_CARETFUNCTION,H19_CREATECARET, (LONG)CD.OwnCaret); } break; case 5 : /* cursor off */ SendMessage(hWndActive,WH19_CARETFUNCTION,H19_HIDECARET,0L); CD.CursorOff = TRUE; break; case 6 : /* keypad shifted */ CD.ShiftedKeypad = TRUE; break; case 7 : /* alternate keypad */ CD.AltKeypad = TRUE; break; case 8 : /* auto lf on cr */ CD.LFonCR = TRUE; break; case 9 : /* auto cr on lf */ CD.CRonLF = TRUE; break; } } void ProcessResetCommand(int ch) { CD.CommandState = NO_COMMAND; switch(ch) { case 1 : if (CD.StatOpen) { CD.StatOpen = FALSE; memset(SW.pVidBuffer, SP, TW.MaxCols); InvalidateRect(SW.hWnd, (LPRECT)NULL, TRUE); UpdateWindow(SW.hWnd); MoveStatWindow(MW.Height); if (hWndActive == SW.hWnd) SendMessage(hWndActive,WH19_CARETFUNCTION,H19_HIDECARET,0L); } break; case 2 : /* enable key click */ CD.KeyClick = TRUE; break; case 3 : /* exit hold screen mode */ CD.HoldScreen = FALSE; break; case 4 : if (CD.BlockCursor) { CD.BlockCursor = FALSE; SendMessage(hWndActive, WH19_CARETFUNCTION,H19_DESTROYCARET, (LONG)CD.OwnCaret); SendMessage(hWndActive, WH19_CARETFUNCTION,H19_CREATECARET, (LONG)CD.OwnCaret); } break; case 5 : /* cursor on */ CD.CursorOff = FALSE; SendMessage(hWndActive,WH19_CARETFUNCTION,H19_SHOWCARET,0L); break; case 6 : /* keypad unshifted */ CD.ShiftedKeypad = FALSE; break; case 7 : /* exit alternate keypad */ CD.AltKeypad = FALSE; break; case 8 : /* no auto lf on cr */ CD.LFonCR = FALSE; break; case 9 : /* no auto cr on lf */ CD.CRonLF = FALSE; break; } } static void NEAR ProcessESCCommand(BYTE ch) { CD.CommandState = NO_COMMAND; switch(ch) { case '#' : /* transmit page */ SendScreen(&TW); break; case '<' : /* enter ansi mode */ CD.ANSIMode = TRUE; break; case '=' : /* enter alternate keypad */ CD.AltKeypad = TRUE; break; case '>' : /* exit alternate keypad */ CD.AltKeypad = FALSE; break; case '@' : /* enter insert char mode */ CD.ICToggle = TRUE; break; case 'A' : /* move cursor up */ SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORUP,1L); break; case 'B' : /* move cursor down */ SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORDOWN,1L); break; case 'C' : /* move cursor right */ SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORRIGHT,1L); break; case 'D' : /* move curosr left */ SendMessage(hWndActive, WH19_COMMAND, H19_MOVECURSORLEFT,1L); break; case 'E' : /* home and clear */ SendMessage(hWndActive, WH19_COMMAND, H19_CLRSCREEN,0L); break; case 'F' : /* enter graphics mode */ CD.GraphicsMode = TRUE; break; case 'G' : /* exit graphics mode */ CD.GraphicsMode = FALSE; break; case 'H' : /* home cursor */ SwitchActiveWindow(TW.hWnd); SendMessage(hWndActive, WH19_COMMAND, H19_CURSORHOME,0L); break; case 'I' : /* reverse line feed */ SendMessage(hWndActive, WH19_COMMAND, H19_REVERSELINEFEED,0L); break; case 'J' : /* clear to end of screen */ SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFSCREEN,0L); break; case 'K' : /* clear to end of line */ SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOENDOFLINE,0L); break; case 'L' : /* insert line */ SendMessage(hWndActive, WH19_COMMAND, H19_INSERTLINE,1L); break; case 'M' : /* delete line */ SendMessage(hWndActive, WH19_COMMAND, H19_DELETELINE,1L); break; case 'N' : /* delete char */ SendMessage(hWndActive, WH19_COMMAND,H19_DELETECHAR,1L); break; case 'O' : /* exit insert char mode */ CD.ICToggle = FALSE; break; case 'Y' : /* position cursor */ CD.CommandState = YPOS_COMMAND; break; case 'Z' : /* identify as VT52 */ if (CD.LineState == IDM_ONLINE) IdentifyTerm(); break; case '[' : /* enter hold screen mode */ CD.HoldScreen = TRUE; break; case '\\' : /* exit hold screen mode */ CD.HoldScreen = FALSE; break; case ']' : /* transmit status line */ SendStatusLine(&SW); break; case 'b' : /* clear to screen top */ SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOTOPOFSCREEN,0L); break; case 'j' : /* save cursor position */ SendMessage(hWndActive, WH19_CURSORPOSITION,H19_SAVECURSOR, 0L); break; case 'k' : /* set to saved position */ PositionRow((BYTE)CD.CurSaveRow); PositionCol((BYTE)CD.CurSaveCol); break; case 'l' : /* erase entire line */ SendMessage(hWndActive, WH19_COMMAND, H19_ERASELINE,0L); break; case 'n' : /* report cursor position */ if (CD.LineState == IDM_ONLINE) { short currow, curcol; SendMessage(hWndActive, WH19_CURSORPOSITION,H19_GETCURSOR, MAKELONG(&currow, &curcol)); ReportCursorPosition(currow,curcol); } break; case 'o' : /* clear to start of line */ SendMessage(hWndActive, WH19_COMMAND, H19_CLRTOSTARTOFLINE,0L); break; case 'p' : /* enter inverse video */ CD.InverseVideo = TRUE; CD.CharAttribute = 0x80; break; case 'q' : /* exit inverse video */ CD.CharAttribute = 0; CD.InverseVideo = FALSE; break; case 'r' : /* set baud rate */ CD.CommandState = SETBAUD_COMMAND; break; case 't' : /* enter shifted keypad */ CD.ShiftedKeypad = TRUE; break; case 'u' : /* exit shifted keypad */ CD.ShiftedKeypad = FALSE; break; case 'v' : /* set wraparound */ CD.WrapAround = TRUE; break; case 'w': /* no wrap */ CD.WrapAround = FALSE; break; case 'x' : /* set command */ CD.CommandState = SET_COMMAND; break; case 'y' : /* reset command */ CD.CommandState = RESET_COMMAND; break; case 'z' : /* reset to power up conditions */ ResetTerminal(); break; case '}' : /* disable keyboard */ CD.KeyboardDisabled = TRUE; break; case '{' : /* enable keyboard */ CD.KeyboardDisabled = FALSE; break; } } /* paint command */ void NEAR MainWndPaint(hWnd, hDC) HWND hWnd; HDC hDC; { register BOOL iconic = IsIconic(hWnd); char *ptr; RECT prect; #if defined(KERMIT) if (krmState) krmShowTransferData(hWnd, hDC, iconic); else #endif if (iconic) { GetClientRect(hWnd, (LPRECT)&prect); ptr = szWinTitle; Rectangle(hDC,prect.left,prect.top,prect.right,prect.bottom); prect.top += 1; DrawText(hDC, (LPSTR)ptr,4,(LPRECT)&prect, DT_CENTER | DT_NOCLIP | DT_EXTERNALLEADING); prect.top = prect.bottom/2; ptr += strlen(szWinTitle) - 5; DrawText(hDC, (LPSTR)ptr,4,(LPRECT)&prect, DT_CENTER | DT_NOCLIP); } } /* called when a system key is activated */ long NEAR MainSysCommand(hWnd,message,wParam,lParam) HWND hWnd; unsigned message; WORD wParam; LONG lParam; { FARPROC fp; switch (wParam) { case IDM_ABOUT: fp = MakeProcInstance((FARPROC)AboutBoxProc, hInst); DialogBox(hInst, MAKEINTRESOURCE(DT_ABOUT),hWnd,fp); FreeProcInstance(fp); return TRUE; default: return(DefWindowProc(hWnd,message,wParam,lParam)); } return (0L); } /* window has been resized */ void NEAR SizeWindow(width, height, code) WORD width; WORD height; WORD code; { #if defined(KERMIT) if (krmState) krmAdjustHeight((short)width, (short)height); #endif switch (code) { case SIZEICONIC: break; default: MW.Height = height; MW.Width = width; MW.BottomTextLine = height / TW.CharHeight * TW.CharHeight - TW.CharHeight; MW.SCBottomTextLine = MW.SCTopTextLine + MW.BottomTextLine; if (IsWindow(hWndActive)) SendMessage(hWndActive, WH19_CARETFUNCTION,H19_DESTROYCARET, (LONG)CD.OwnCaret); if (IsWindow(TW.hWnd)) { MoveWindow(TW.hWnd,0,0,TW.Width,TW.Height,TRUE); if (IsWindow(SW.hWnd)) MoveStatWindow(MW.Height); } if (IsWindow(hWndActive)) SendMessage(hWndActive, WH19_CARETFUNCTION,H19_CREATECARET, (LONG)CD.OwnCaret); break; } } /* move status window */ static void NEAR MoveStatWindow(short height) { register short statpos = TW.Height; register short statheight = TW.CharHeight; CD.StatOverlayTerm = FALSE; if ((statpos + statheight) > height) { if (CD.StatOpen) { statpos = MW.BottomTextLine; statheight = MW.Height - MW.BottomTextLine; CD.StatOverlayTerm = TRUE; } else { statpos = MW.BottomTextLine + TW.CharHeight; statheight = height - statpos; } } MoveWindow(SW.hWnd,0,statpos,TW.Width,statheight,TRUE); } /* menu handler */ void NEAR WndCommand(hWnd, wparam, lparam) HWND hWnd; WORD wparam; LONG lparam; { register HMENU hMenu = GetMenu(hWnd); HCURSOR hCurOld; FARPROC fp; switch (wparam) { case IDM_CLEARCOM: FlushComm(cid,0); FlushComm(cid,1); EscapeCommFunction(cid,SETXON); if (CD.LineState == IDM_ONLINE) TransmitCommChar(cid, XON); break; case IDM_RESET: ResetTerminal(); break; case IDM_OFFLINE: SetWindowLong(MW.hWnd, GWL_WNDPROC, (LONG)MainWndSubclassProc); hCurOld = SetCursor(LoadCursor((HANDLE)NULL,IDC_WAIT)); SendMessage(hWndActive, WH19_CARETFUNCTION, H19_HIDECARET, 0L); ChangeMenu(hMenu,IDM_OFFLINE,(LPSTR)szOnline,IDM_ONLINE, MF_BYCOMMAND | MF_CHANGE); DrawMenuBar(hWnd); CD.LineState = IDM_ONLINE; SendMessage(hWndActive, WH19_CARETFUNCTION, H19_SHOWCARET, 0L); SetCursor(hCurOld); break; case IDM_ONLINE: SetWindowLong(MW.hWnd, GWL_WNDPROC, (LONG)fpTerminal); hCurOld = SetCursor(LoadCursor((HANDLE)NULL,IDC_WAIT)); SendMessage(hWndActive, WH19_CARETFUNCTION, H19_HIDECARET, 0L); ChangeMenu(hMenu,IDM_ONLINE,(LPSTR)szOffline,IDM_OFFLINE, MF_BYCOMMAND | MF_CHANGE); DrawMenuBar(hWnd); CD.LineState = IDM_OFFLINE; SendMessage(hWndActive, WH19_CARETFUNCTION, H19_SHOWCARET, 0L); SetCursor(hCurOld); break; case IDM_COMM: fp = MakeProcInstance((FARPROC)SetCommParams, hInst); DialogBox(hInst, MAKEINTRESOURCE(DT_COMM),hWnd,fp); FreeProcInstance(fp); break; case IDM_TERM: fp = MakeProcInstance((FARPROC)SetTermParams, hInst); DialogBox(hInst, MAKEINTRESOURCE(DT_TERM),hWnd,fp); FreeProcInstance(fp); break; case IDM_SPECIALKEYS: fp = MakeProcInstance((FARPROC)SetStringParams, hInst); DialogBox(hInst, MAKEINTRESOURCE(DT_STRING),hWnd,fp); FreeProcInstance(fp); break; case IDM_COPY: SendMessage(TW.hWnd, WH19_SLAPSCREEN, 0, 0L); break; case IDM_PASTE: if (OpenClipboard(hWnd)) { LPSTR lpClip, lpDest; BYTE ch; hClipData = GetClipboardData(CF_TEXT); GB.lBufSize = GlobalSize(hClipData); if (GB.hBuf == NULL) { GB.hBuf = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, GB.lBufSize); if (GB.hBuf != NULL) { GB.lBufHead = GB.lBufTail = 0; lpClip = GlobalLock(hClipData); lpDest = GlobalLock(GB.hBuf); while(ch = *lpClip++) { if (ch != LF) { *lpDest++ = ch; GB.lBufTail += 1; } } GlobalUnlock(hClipData); GlobalUnlock(GB.hBuf); } } CloseClipboard(); } break; #if defined(KERMIT) default: krmProcessKermitMenu(hWnd, wparam); break; #endif } } /* communications processor */ void NEAR ProcessComm() { COMSTAT ComStatus; int num; register int retresult = 0; register int result = 0; static char Buffer[RXQUESIZE]; static int bufsize = 0; if ((CD.LineState == IDM_ONLINE) && !CD.ScrollLock) { if (bufsize == 0) { GetCommError(cid, (COMSTAT FAR *)&ComStatus); if (num = ComStatus.cbInQue) { num = min(num, BUFSIZE); if ((result = ReadComm(cid, (LPSTR)Buffer, num)) < 0) { result = -result; Buffer[result] = NUL; } } } else result = bufsize; #if defined(KERMIT) if (krmState) krmKermitDispatch(MW.hWnd, Buffer, result); else #endif if (result) { retresult = H19StringInput(Buffer, result); if (retresult) { bufsize = retresult; memmove(Buffer, Buffer+result-retresult,retresult); Buffer[bufsize] = 0; } else bufsize = 0; } else if (GB.hBuf) { BYTE FAR *tbuf; LONG BufBytesRemaining; int count; BufBytesRemaining = GB.lBufTail - GB.lBufHead; if (BufBytesRemaining > 0) { tbuf = GlobalLock(GB.hBuf) + GB.lBufHead; if (BufBytesRemaining > INT_MAX) count = TW.MaxCols; else count = min(TW.MaxCols, (int)LOWORD(BufBytesRemaining)); WriteToPort(cid, tbuf, count); GB.lBufHead += count; BufBytesRemaining = GB.lBufTail - GB.lBufHead; GlobalUnlock(GB.hBuf); } if (BufBytesRemaining <= 0) GB.hBuf = GlobalFree(GB.hBuf); } } } /* write to comm port */ void NEAR WriteToPort(cid, buf, len) short cid; BYTE FAR *buf; int len; { COMSTAT mystat; register int room; GetCommError(cid, (COMSTAT FAR *)&mystat); room = TXQUESIZE - mystat.cbOutQue; while (room < len) { if (!DoMessage()) { GetCommError(cid, (COMSTAT FAR *)&mystat); room = TXQUESIZE - mystat.cbOutQue; } } WriteComm(cid, (LPSTR)buf, len); } /* change baud rate */ static void NEAR ProcessBaudChange(int ch) { WORD rate; CD.CommandState = NO_COMMAND; if ((ch >= 0) && (ch < BAUDTABLESIZE)) { CommData.BaudRate = rate = BaudRateTable[ch]; CommData.StopBits = ONESTOPBIT; if (rate == 110) CommData.StopBits = TWOSTOPBITS; SetCommState((DCB FAR *)&CommData); } } /* report vt52 */ static void NEAR IdentifyTerm() { BYTE outstr[5]; outstr[0] = ESC; outstr[1] = '/'; outstr[2] = 'K'; WriteToPort(cid, (BYTE FAR *)outstr, 3); } /* report cursor position */ static void NEAR ReportCursorPosition(short line, short col) { BYTE outstr[20]; register BYTE *outstrptr = outstr; *outstrptr++ = ESC; if (CD.ANSIMode) { *outstrptr++ = '['; itoa(line+1, outstrptr,10); outstrptr += strlen(outstrptr); *outstrptr++ = ';'; itoa(col+1, outstrptr,10); outstrptr += strlen(outstrptr); *outstrptr++ = 'R'; } else { *outstrptr++ = 'Y'; *outstrptr++ = (BYTE)(SP + line); *outstrptr++ = (BYTE)(SP + col); } *outstrptr = NUL; WriteToPort(cid, (BYTE FAR *)outstr, strlen(outstr)); }