home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
progjorn
/
pj_7_1.arc
/
WINH19FN.C
< prev
Wrap
Text File
|
1988-10-23
|
15KB
|
532 lines
/*
* 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);
}
}
}