/*
 * Windows H19 Terminal Emulator
 * 
 * Written by William S. Hall
 *	      3665 Benton Street, #66
 *	      Santa Clara, CA 95051
 *
 * Program entry module
 */

#define NOKANJI
#define NOATOM
#include <windows.h>
#include <string.h>

#define EXTERN
#define INITIALIZE

#include "winasc.h"
#include "winh19.h"
#include "win19d.h"

#if defined(KERMIT)
#include "winkpf.h"
extern krmState;
#endif

static BOOL NEAR OutputKeydown(BYTE str[], int *plen, WORD wparam);
static void NEAR ScanForEscapes(BYTE *str, int *len);
static void NEAR SetScrollState(void);

/* Entry point */
int FAR PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, cmdShow)
HANDLE hInstance, hPrevInstance;
LPSTR lpszCmdLine;
short cmdShow;
{

    if (!InitProgram(hInstance,hPrevInstance, lpszCmdLine, cmdShow))
	return FALSE;

    while (TRUE)
	if (!DoMessage())
	    ProcessComm();
}

/* Main window procedure */
long FAR PASCAL MainWndProc(hWnd,message,wParam,lParam)
HWND hWnd;
unsigned message;
WORD wParam;
LONG lParam;
{

    PAINTSTRUCT ps;

    switch(message) {

   	case WM_CHANGECBCHAIN:
	    if (wParam == hWndNext)
		hWndNext = LOWORD(lParam);
	    SendMessage(hWndNext, message, wParam, lParam);
	    break;

	case WM_DRAWCLIPBOARD:
	    if (IsWindow(hWndNext))
		SendMessage(hWndNext, message, wParam, lParam);
	    if (OpenClipboard(hWnd)) {
		HMENU hMenu = GetMenu(hWnd);
		hClipData = GetClipboardData(CF_TEXT);
		if (hClipData != NULL)
		    EnableMenuItem(hMenu, IDM_PASTE, MF_ENABLED);
		else
		    EnableMenuItem(hMenu, IDM_PASTE, MF_GRAYED);
		CloseClipboard();
	    }
	    break;

	case WM_CREATE:
	    MainWndCreate(hWnd,lParam);
	    break;

	case WM_KEYDOWN:
	    if (!CD.KeyboardDisabled)
	        H19LocalKeyDown(wParam);
	    break;

	case WM_CHAR:
	    if (!CD.KeyboardDisabled)
	        H19StringInput((BYTE *)&wParam,(short)1);
	    break;

	case WM_SETFOCUS:
	    CD.OwnCaret = TRUE;
	    if (IsWindowEnabled(hWnd) && IsWindow(hWndActive)) {
		SendMessage(hWndActive, WH19_CARETFUNCTION, H19_CREATECARET,
				(LONG)CD.OwnCaret);
	    }
	    break;

	case WM_KILLFOCUS:
	    if (IsWindow(hWndActive)) {
		SendMessage(hWndActive,WH19_CARETFUNCTION,H19_DESTROYCARET,
				(LONG)CD.OwnCaret);
	    }
	    CD.OwnCaret = FALSE;
	    break;

	case WM_COMMAND:
	    WndCommand(hWnd, wParam, lParam);
	    break;

	case WM_MOVE:
	    MW.SCTopTextLine = HIWORD(lParam);
	    MW.SCBottomTextLine = MW.SCTopTextLine + MW.BottomTextLine;
	    break;

	case WM_SIZE:
	    SizeWindow(LOWORD(lParam), HIWORD(lParam), wParam);
	    break;

	case WM_CLOSE:
	    CloseCommPort(hWnd, &cid);
	    ChangeClipboardChain(hWnd, hWndNext);
	    DestroyWindow(hWnd);
	    break;

	case WM_ENDSESSION:
	    if (wParam)
	        CloseCommPort(hWnd, &cid);
	    break;

	case WM_DESTROY:
	    PostQuitMessage(0);
	    break;

	case WM_PAINT:
	    BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
	    MainWndPaint(hWnd, ps.hdc);
	    EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
	    break;

	case WM_SYSCOMMAND:
            return((long)MainSysCommand(hWnd, message, wParam,lParam));

	default:
	    return ((long)DefWindowProc(hWnd,message,wParam,lParam));
    }
    return(0L);
}

/* Subclass window procedure */
LONG FAR PASCAL MainWndSubclassProc(hWnd, message, wParam, lParam)
HWND hWnd;
unsigned message;
WORD wParam;
LONG lParam;
{

    BYTE outstr[80];
    int len = 0;
    register BOOL CheckForControl = FALSE;

    switch(message) {

	case WM_CHAR:
#if defined(KERMIT)
	    if (!(CD.KeyboardDisabled || krmState))
#else
	    if (!CD.KeyboardDisabled)
#endif
	        outstr[len++] = (BYTE)wParam;
	        break;

	case WM_KEYDOWN:
	    if (wParam == VK_CANCEL) {
		if (CD.BreakFlag == -1)
		    CD.BreakFlag = SetCommBreak(cid);
 	        break;
	    }
	    else if (wParam == VK_SCROLL) {
		SetScrollState();
		break;
	    }

#if defined(KERMIT)
	    if (!(CD.KeyboardDisabled || krmState)) {
#else
	    if (!CD.KeyboardDisabled) {
#endif
		switch(wParam) {

		    case VK_BACK:
			if (GetKeyState(VK_CONTROL) & 0x8000)
			    outstr[len++] = DEL;
			break;

		    default:
			CheckForControl = OutputKeydown(outstr, &len, wParam);
			break;
		}
	    }
	    break;		

   	case WM_COMMAND:
	    if ((wParam >= IDM_F1) && (wParam <= IDM_CSF12)) {
#if defined(KERMIT)
	    	if (!(CD.KeyboardDisabled || krmState)) {
#else
	    	if (!CD.KeyboardDisabled) {
#endif
		    char *tptr;
		    int sparam, index;
		    sparam = (wParam /100) * 100;
		    index = wParam - sparam;
		    switch (sparam) {
		        case IDM_F1:
			    tptr = szFKey[index];
	        	    break;
		        case IDM_SF1:
			    tptr = szSFKey[index];
	         	    break;
			case IDM_CF1:
			    tptr = szCFKey[index];
		            break;
		        case IDM_CSF1:
			    tptr = szCSFKey[index];
			    break;
		    }
        	    len = GetProfileString((LPSTR)szAppName,(LPSTR)tptr,
						    (LPSTR)"",(LPSTR)outstr,80);
		    ScanForEscapes(outstr, &len);
		    break;		
		}
		break;
	    }
	    return(CallWindowProc(fpTerminal,hWnd,message,wParam,lParam));

	case WM_KEYUP:
	    if (wParam == VK_CANCEL) {
                ClearCommBreak(cid);
		CD.BreakFlag = -1;
		break;
	    }

	default:
	    return(CallWindowProc(fpTerminal,hWnd,message,wParam,lParam));
    }
    if (CheckForControl)
	if (GetKeyState(VK_CONTROL) & 0x8000)
	    return(CallWindowProc(fpTerminal,hWnd,message,wParam,lParam));
    if (len) {
	WriteToPort(cid, (BYTE FAR *)outstr, len);
	if (!CD.FullDuplex)
	    return(CallWindowProc(fpTerminal,hWnd,message,wParam,lParam));
    }
    return 0L;
}

static BOOL NEAR OutputKeydown(BYTE str[], int *plen, WORD wparam)
{

    register BOOL result = FALSE;
    register int index;

    str[(*plen)++] = ESC;
    if (CD.ANSIMode)
	str[(*plen)++] = '[';

    switch(wparam) {
        case VK_UP:
	    str[(*plen)++] = 'A';
	    result = TRUE;	    	
	    break;
        case VK_DOWN:
	    str[(*plen)++] = 'B';
	    result = TRUE;	    	
	    break;
	case VK_RIGHT:
	    str[(*plen)++] = 'C';
	    result = TRUE;	    	
	    break;
	case VK_LEFT:
	    str[(*plen)++] = 'D';
	    result = TRUE;	    	
	    break;
	case VK_HOME:
	    if (CD.ANSIMode) {
		str[(*plen)++] = '4';
	        if (CD.ICToggle)
		    str[(*plen)++] = 'l';
	        else
		    str[(*plen)++] = 'h';
	    }
	    else {
	        if (CD.ICToggle)
		    str[(*plen)++] = 'O';
	        else
		    str[(*plen)++] = '@';
	    }
	    result = TRUE;
	    break;
	case VK_END:
	    str[(*plen)++] = 'L';
	    result = TRUE;	    	
	    break;
	case VK_PRIOR:
	    if (CD.ANSIMode)
	        str[(*plen)++] = 'P';
	    else
	        str[(*plen)++] = 'N';
	    result = TRUE;
	    break;
	case VK_NEXT:
	    str[(*plen)++] = 'M';
	    result = TRUE;	    	
	    break;
	case VK_CLEAR:
	    str[(*plen)++] = 'H';
	    result = TRUE;	    	
	    break;

	case VK_F1:
	case VK_F2:
	case VK_F3:
	case VK_F4:
	case VK_F5:
	case VK_F7:
	case VK_F8:
	case VK_F9:
	    if (wparam >= VK_F7)
	        index = 'P' + wparam - VK_F7;
	    else
	        index = 'S' + wparam - VK_F1;
	    if (CD.ANSIMode)
	        str[*plen - 1] = 'O';
	    str[(*plen)++] = (BYTE)index;
	    break;

	case VK_F6:
	    if (GetKeyState(VK_SHIFT) & 0x8000) {
		if (CD.ANSIMode) {
		     str[(*plen)++] = '2';
		     str[(*plen)++] = 'J';
		}
		else
		    str[(*plen)++] = 'E';
	    }
	    else
	        str[(*plen)++] = 'J';
	    result = TRUE;
	    break;

	case VK_NUMPAD0:
	case VK_NUMPAD1:
	case VK_NUMPAD2:
	case VK_NUMPAD3:
	case VK_NUMPAD4:
	case VK_NUMPAD5:
	case VK_NUMPAD6:
	case VK_NUMPAD7:
	case VK_NUMPAD8:
	case VK_NUMPAD9:
	case VK_DECIMAL:
	    if (CD.AltKeypad) {
		if (CD.ANSIMode)
		    str[*plen - 1] = 'O';
		else
		    str[(*plen)++] = '?';
		if (wparam == VK_DECIMAL)
		    str[(*plen)++] = 'n';
		else
	            str[(*plen)++] = (BYTE)('p' + (wparam - VK_NUMPAD0));
	    }
	    else
		*plen = 0;
	    break;
	default:
	    *plen = 0;
	    break;
    }
    return(result);
}

static void NEAR ScanForEscapes(BYTE *str, int *len)
{

     register int i, j;
     int inlen = min(*len, 79);
     BYTE buf[80], ch;

     for (i = 0, j = 0; i < inlen; i++) {
	if ((ch = str[i]) == '\\') {
	    ch = str[++i];
	    if (('@' <= ch) && (ch <= '['))
		ch ^= 64;
	}
	buf[j++] = ch;
     }
     buf[j] = NUL;
     strcpy(str, buf);
     *len = j;
}

static void NEAR SetScrollState()
{

    CD.ScrollLock = GetKeyState(VK_SCROLL) & 1;
    if (GetKeyState(VK_SHIFT) & 0x8000)
	CD.ReleaseCount = TW.MaxLines - 1;
    else
	CD.ReleaseCount = 0;

}

void BroadcastWinIniChange()
{

    SendMessage((HWND)-1, WM_WININICHANGE, 0, (LONG)(LPSTR)szAppName);

}

