home *** CD-ROM | disk | FTP | other *** search
- /*
- * Windows H-19 emulator
- *
- * Written by William S. Hall
- * 3665 Benton Street, #66
- * Santa Clara, CA 95051
- *
- * Emulator function support module - extracts
- */
-
- /*
- * If the terminal is off-line, then the keypad keys
- * on an H-19 send the appropriate escape sequence
- * back to the terminal. We emulate this behavior here.
- * This function is called from the main window procedure when
- * a WM_KEYDOWN key is received.
- */
- void NEAR H19LocalKeyDown(WORD keycode)
- {
- /*
- * Since the child windows act as the H-19 screen and status line,
- * we simply pass on the appropriate action to the active window.
- */
- 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: /* insert character toggle */
- 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;
-
- }
- }
-
- /*
- * Message processing loop. Return false if no message.
- */
- BOOL NEAR DoMessage()
- {
-
- MSG msg;
-
- /*
- * Look for a message. If we have one, remove and process it.
- */
- if (PeekMessage((LPMSG)&msg,NULL,0,0,PM_REMOVE)) {
- /*
- * have to exit.
- */
- if (msg.message == WM_QUIT)
- exit((int)msg.wParam);
- /*
- * got a key from accelator table. All shifted, control,
- * and shifted-control function keys are in this table.
- * We convert them to a WM_COMMAND message and process them there.
- */
- if (TranslateAccelerator(MW.hWnd,hAccel,(LPMSG)&msg) == 0) {
- /*
- * DoKeyTranslation is our own function. Here we
- * decide if a key down/up message should be translated to
- * a WM_CHAR message, or if the wParam should be changed
- * to another virtual key code. If true is returned, the
- * key is translated.
- */
- if (DoKeyTranslation(msg.message, &msg.wParam))
- TranslateMessage((LPMSG)&msg);
- /*
- * Tell Windows to call our message procedure.
- */
- DispatchMessage((LPMSG)&msg);
- }
- return TRUE;
- }
- return FALSE;
- }
-
- /*
- * Return TRUE if key is to be translated.
- */
- static BOOL NEAR DoKeyTranslation(unsigned message, WORD *wparam)
- {
-
- unsigned shiftstate, numstate;
- int retval = TRUE;
-
- /*
- * if we translate VK_CANCEL, it will become a CTRL-C. Since
- * we want to use this key for other purposes, we prevent
- * its translation by returning false.
- */
- if ((message == WM_KEYDOWN) || (message == WM_KEYUP)) {
- if (*wparam == VK_CANCEL)
- return FALSE;
-
- /*
- * Similarly, if the virtual key corresponding to the backspace
- * is pressed along with the control key, then we inhibit translation.
- */
- if (*wparam == VK_BACK) {
- if (GetKeyState(VK_CONTROL) & 0x8000)
- return FALSE;
- return TRUE;
- }
-
- /*
- * In the following code, we examine and determine if a key's
- * virtual key code should be changed and/or translated.
- * The situation depends on the state of the H-19 shifted
- * and alternate keypad status as well as the state of
- * the PC's numlock and shift keys. The correct responses
- * were obtained only by endless experimentation.
- *
- * The main problem is that VK_NUMPAD keys, if translated,
- * become WM_CHAR keys with the numeric valuse 0 to 9 and
- * the decimal point. This must be prevented, especially
- * when alternate key sequences, i. e. ESC ? v for example,
- * must be sent by the keypad.
- */
- 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;
- }
-
- /*
- * Find out if a virtual key is from the numpad set.
- */
- static BOOL NEAR InNumpadSet(unsigned val)
- {
-
- return(((val >= VK_NUMPAD0) && (val <= VK_NUMPAD9)) || (val == VK_DECIMAL));
-
- }
-
- /*
- * Change a numpad virtual key code to the corresponding numeric
- * pad code. Note that numpad keys, if allowed to be translated,
- * become the digits 0 to 9 and the decimal key.
- */
- 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;
- }
-
- /*
- * Take care of the insert/delete keys in a short table.
- * Sometimes it is not necessary to check the whole list because
- * we only have to correct the workings of the 0 and decimal keys.
- */
- static WORD NEAR EditToNumpadShort(unsigned val)
- {
- switch (val) {
- case VK_DELETE:
- val = VK_DECIMAL;
- break;
- case VK_INSERT:
- val = VK_NUMPAD0;
- break;
- }
- return val;
- }
-
- /*
- * This is called if all the keys must be scanned.
- */
- 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. The string is scanned
- * for an ESCAPE character. If seen, the scanned string is
- * dispatched to the terminal window for display. Then,
- * the escape sequence is handled. Frequently, the sequence
- * is broken between strings.
- */
- 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);
- }
-
- /*
- * This routine handles the menu and accelerator keys
- */
- void NEAR WndCommand(hWnd, wparam, lparam)
- HWND hWnd;
- WORD wparam;
- LONG lparam;
- {
-
- HMENU hMenu;
- HCURSOR hCurOld;
- FARPROC fp;
- int result;
-
- hMenu = GetMenu(hWnd);
-
- switch (wparam) {
- case IDM_RESET:
- ResetTerminal();
- break;
- /*
- * When going from off-line to on-line, the window proc for
- * the main window is changed to the subclass window procedure.
- * In addition, the caret has to be taken down and regenerated
- * and the menu redrawn.
- */
- 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;
- /*
- * A similar process happens here when going from on-line to off-line
- */
- 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;
- /*
- * The next three commands bring up dialog boxes to change settings.
- */
- case IDM_COMM:
- fp = MakeProcInstance((FARPROC)SetCommParams, hInst);
- result = DialogBox(hInst, MAKEINTRESOURCE(DT_COMM),hWnd,fp);
- break;
- case IDM_TERM:
- fp = MakeProcInstance((FARPROC)SetTermParams, hInst);
- result = DialogBox(hInst, MAKEINTRESOURCE(DT_TERM),hWnd,fp);
- break;
- case IDM_SPECIALKEYS:
- fp = MakeProcInstance((FARPROC)SetStringParams, hInst);
- result = DialogBox(hInst, MAKEINTRESOURCE(DT_STRING),hWnd,fp);
- break;
- /*
- * Most of the action here takes place in the routine
- * which handles the child terminal window. Here we just
- * sent it a message to do it. Of course, we had to
- * write the code on the other side to handle it, as well!
- */
- case IDM_COPY:
- SendMessage(TW.hWnd, WH19_SLAPSCREEN, 0, 0L);
- break;
- /*
- * This piece of code opens the clipboard and copies it to
- * to a buffer. Later, each line of the buffer is read
- * by the communications processor and sent out the comm port.
- */
- 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;
- }
- }
-
- /*
- * This complicated routine reads the comm port when on-line provided
- * the buffer is empty. Otherwise, it looks to see if anything
- * is left over from a previous attempt at processing. Normally,
- * the buffer is completely emptied when it is sent to the main
- * window procedure. However, if hold-screen is in effect, then
- * the terminal window will stop display whenever a carriage return
- * is seen. In this case, the remaining buffer remains unprocessed
- * until the scroll-lock key is toggled and another line (or screen)
- * can be displayed.
- */
- void NEAR ProcessComm()
- {
-
- COMSTAT ComStatus;
- int num;
- int retresult = 0;
- int result = 0;
-
- static char Buffer[COMMQUESIZE];
- static int bufsize = 0;
-
- /* if on line, continue */
- if ((CD.LineState == IDM_ONLINE) && !CD.ScrollLock) {
- /* if the buffer is empty, read the comm port */
- if (bufsize == 0) {
- GetCommError(cid, (COMSTAT FAR *)&ComStatus);
- /* if we find something in the comm buffer, get it */
- if (num = ComStatus.cbInQue) {
- num = min(num, BUFSIZE);
- /* if error, ignore it and pass the string along anyway */
- if ((result = ReadComm(cid, (LPSTR)Buffer, num)) < 0) {
- result = -result;
- Buffer[result] = NUL;
- }
- }
- }
- else
- result = bufsize;
-
- /*
- * We got something on the last read, or the buffer was not empty
- * because the previous dispatch did not read all of it.
- */
- if (result) {
- retresult = H19StringInput(Buffer, result);
- /* if still not empty, move remaining to front of buffer */
- if (retresult) {
- bufsize = retresult;
- memmove(Buffer, Buffer+result-retresult,retresult);
- Buffer[bufsize] = 0;
- }
- else
- bufsize = 0;
- }
- /*
- * If nothing immediate to process, then check out global buffer
- * in case something from the clipboard is there.
- */
- else if (GB.hBuf) {
- BYTE FAR *tbuf;
- LONG BufBytesRemaining;
- int count;
-
- /* if not empty, then get another line from buffer */
- 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));
- /* send it to the port */
- WriteToPort(cid, tbuf, count);
- GB.lBufHead += count;
- BufBytesRemaining = GB.lBufTail - GB.lBufHead;
- GlobalUnlock(GB.hBuf);
- }
- if (BufBytesRemaining <= 0)
- GB.hBuf = GlobalFree(GB.hBuf);
- }
- }
- }