/*
 * Windows H19 Terminal Emulator - less frequently used functions
 * 
 * Written by William S. Hall
 *	      3665 Benton Street, #66
 *	      Santa Clara, CA 95051
 */

#define NOKANJI
#define NOATOM
#define NOMINMAX
#include <windows.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>

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

/* local functions */
static void NEAR LoadBuf(BYTE FAR *dest, BYTE FAR *source, int count);
static void NEAR LoadOneLine(BYTE FAR *, BYTE *, short, BOOL);
static void NEAR LoadPrefixAndData(int, int, BYTE *, BYTE FAR *, int);
static void NEAR TermParamInit(HWND hDlg);
static void NEAR TermParamSet(HWND hDlg);
static void NEAR SaveCommParams(void);
static void NEAR SetDefaultPort(void);
static void NEAR StringOp(HWND hDlg, WORD param);

/* about box window procedure */
BOOL FAR PASCAL AboutBoxProc(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{

    switch (message) {
	case WM_INITDIALOG:
	    break;
	case WM_COMMAND:
	    switch (wParam) {
		case IDOK:
		case IDCANCEL:
		    EndDialog(hDlg,TRUE);
		    break;
		default:
		    return FALSE;
	    }
	    break;

	default:
	    return FALSE;
    }
    return TRUE;
}

/* close communications port */
void CloseCommPort(HWND hWnd, short *pCid)
{

    if (*pCid >=0) {
        if (CloseComm(*pCid) >= 0)
            *pCid = INT_MIN;
	else 
	    ShowMessage(hWnd, IDS_CANNOTCLOSECOM);
    }
}

/* show message box */
void ShowMessage(HWND hWnd, int msgnum)
{

    char szMessage[80];

    LoadString(hInst, msgnum, (LPSTR)szMessage,sizeof(szMessage));
    
    MessageBox(hWnd,(LPSTR)szMessage, (LPSTR)szAppName, 
		MB_ICONHAND | MB_OK);

}

/* reset the terminal to power up */
void ResetTerminal()
{

    BOOL *ptr, *ptr1;
    int i;

    SendMessage(hWndActive,WH19_CARETFUNCTION,
			H19_DESTROYCARET,(LONG)CD.OwnCaret);
    hWndActive = TW.hWnd;

    ptr = &CD.BlockCursor;
    ptr1 = &S402.BlockCursor;
    for (i = 0; i < 8; i++)
	*ptr++ = *ptr1++;

    ProcessResetCommand(1);	/* turn off status line */

    CD.InverseVideo = FALSE;
    CD.GraphicsMode = FALSE;
    CD.ICToggle = FALSE;
    CD.HoldScreen = FALSE;
    CD.CursorOff = FALSE;
    CD.KeyboardDisabled = FALSE;
    CD.AltKeypad = FALSE;
    CD.CommandState = NO_COMMAND;
    CD.CurSaveRow = CD.CurSaveCol = 0;

    SendMessage(hWndActive, WH19_COMMAND, H19_CLRSCREEN,0L);

    CommData.BaudRate = S401.BaudRate;
    CommData.ByteSize = S401.ByteSize;
    CommData.Parity = S401.Parity;
    CommData.StopBits = S401.StopBits;

    if ( SetCommState((DCB FAR *)&CommData) < 0)
	ShowMessage(MW.hWnd, IDS_NOCOMSET);

    SendMessage(hWndActive,WH19_CARETFUNCTION,
			H19_CREATECARET,(LONG)CD.OwnCaret);

}

/* transmit status line */
void SendStatusLine(PTWND pSW)
{

    BYTE outstr[2];
    BYTE FAR *lpgBuf;
    register short cols = pSW->MaxCols;
    
    if ((CD.StatOpen) && (CD.LineState == IDM_ONLINE)) {
	if (GB.hBuf == NULL) {
	    if (CD.ANSIMode)
		GB.lBufSize = 10 * cols + 2;
	    else 
	        GB.lBufSize = 5 * cols + 2;
	    GB.hBuf = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,GB.lBufSize);
	    if (GB.hBuf != NULL) {
		GB.lBufHead = GB.lBufTail = 0;
	        lpgBuf = GlobalLock(GB.hBuf);
		LoadOneLine(lpgBuf, pSW->pVidBuffer, cols, TRUE);
		outstr[0] = CR;
	        LoadBuf(lpgBuf + GB.lBufTail, (BYTE FAR *)outstr,1);
	        GB.lBufTail += 1;
		GlobalUnlock(GB.hBuf);
	    }
	}
    }
    MessageBeep(0);
}

/* transmit screen contents */
void SendScreen(PTWND pTW)
{

    short lines = pTW->MaxLines;
    register short cols = pTW->MaxCols; 
    BYTE *pBuf = pTW->pVidBuffer;
    BYTE *lineptr = pBuf + pTW->oTopLine;
    BYTE *pEnd = pBuf + pTW->oVidLastLine;
    register int i;
    BYTE outstr[2];
    BYTE FAR *lpgBuf;
    int state;

    if (CD.LineState == IDM_ONLINE) {
	if (GB.hBuf == NULL) {
	    if (CD.ANSIMode)
	        GB.lBufSize = 10 * pTW->ScreenSize + 2;
	    else
		GB.lBufSize = 5 * pTW->ScreenSize  + 2;
	    GB.hBuf = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,GB.lBufSize);
	    if (GB.hBuf != NULL) {
		GB.lBufHead = GB.lBufTail = 0;
	        lpgBuf = GlobalLock(GB.hBuf);
	        for (i = 0; i < lines; i++) {
		    if (i == 0)
			state = TRUE;
		    else
			state = FALSE;
		    LoadOneLine(lpgBuf, lineptr, cols, state);
		    if ((lineptr += cols) >pEnd)
	                lineptr = pBuf;
		}
		outstr[0] = CR;
	        LoadBuf(lpgBuf + GB.lBufTail, (BYTE FAR *)outstr,1);
	        GB.lBufTail += 1;
		GlobalUnlock(GB.hBuf);
	    }
	}
    }
    MessageBeep(0);
}

/* transmit screen support arrays */
#define NC	0
#define NG	1
#define IC	2
#define IG	3

/* old mode across, new mode down */
static BYTE *ANSITransitionCmd[4][4] = {
    "",		"\033[11m",	"\033[m",	"\033[11m\033[m",
    "\033[10m",	"",		"\033[m\033[10m","\033[m",
    "\033[7m",	"\033[11m\033[7m","",		"\033[11m",
    "\033[10m\033[7m","\033[7m","\033[10m",	"",
};
static BYTE *HeathTransitionCmd[4][4] = {
    "",		"\033G",	"\033q",	"\033G\033q",
    "\033F",	"",		"\033F\033q",	"\033q",
    "\033p",	"\033G\033p",	"",		"\033G",
    "\033F\033p","\033p",	"\033F",	"",
};

/* load a line into the global buffer and add escape codes */
static void NEAR LoadOneLine(BYTE FAR *lpgBuf,BYTE *pBuf,
			short len,BOOL resetflag)
{

    BYTE tBuf[TERMMAXCOLS + 10];
    int i = 0;
    short linewidth = len;
    register int j;
    register BYTE ch;
    static int oldmode, newmode;

    if (resetflag)
	newmode = NC;

    while (i < linewidth) {
	for (j = 0; j < linewidth - i; j++) {
	    if (((ch = *pBuf) < DEL) && (ch >= SP)) {	/* normal */
		tBuf[j] = ch;
		pBuf++;
	    }
	    else
		break;
	}
	if (j > 0) {
	    oldmode = newmode;
	    newmode = NC;
	    LoadPrefixAndData(oldmode, newmode, tBuf, lpgBuf, j);
	    i += j;
	}
        for (j = 0; j < linewidth - i; j++) {
	    if (((ch = *pBuf) < 255) && (ch >= 160)) {	/* inverse */
		tBuf[j] = ch & 0x7f;
		pBuf++;
	    }
	    else
		break;
	}
	if (j > 0) {
	    oldmode = newmode;
	    newmode = IC;
	    LoadPrefixAndData(oldmode, newmode, tBuf, lpgBuf, j);
	    i += j;
	}
        for (j = 0; j < linewidth - i; j++) {		/* normal graphics */
	    if ( (((ch = *pBuf) < SP) && (ch >= 0)) || (ch == DEL)) {
		tBuf[j] = (ch == DEL ? ch - 1 : ch + 94);
		pBuf++;
	    }
	    else
		break;
	}
	if (j > 0) {
	    oldmode = newmode;
	    newmode = NG;
	    LoadPrefixAndData(oldmode, newmode, tBuf, lpgBuf, j);
	    i += j;
	}
        for (j = 0; j < linewidth - i; j++) {		/* inverse graphics */
	    if ( (((ch = *pBuf) < 160) && (ch > DEL)) || (ch == 255)) {
		ch &= 0x7f;
		tBuf[j] = (ch == DEL ? ch - 1 : ch + 94);
		pBuf++;
	    }
	    else
		break;
	}
	if (j > 0) {
	    oldmode = newmode;
	    newmode = IG;
	    LoadPrefixAndData(oldmode, newmode, tBuf, lpgBuf, j);
	    i += j;
	}
    }
}

/* support routine for load one line */
static void NEAR LoadPrefixAndData(int oldmode, int newmode, 
					BYTE *tBuf, BYTE FAR * lpgBuf, int j)
{

    register short cmdlen;
    register BYTE *cmdstr;

    if (CD.ANSIMode)
        cmdstr = ANSITransitionCmd[newmode][oldmode];
    else 
	cmdstr = HeathTransitionCmd[newmode][oldmode];
    cmdlen = strlen(cmdstr);
    LoadBuf(lpgBuf + GB.lBufTail, (BYTE FAR *)cmdstr, cmdlen);
    GB.lBufTail += cmdlen;
    LoadBuf(lpgBuf + GB.lBufTail, (BYTE FAR *)tBuf, j);
    GB.lBufTail += j;
}

/* long pointer strncpy */
static void NEAR LoadBuf(BYTE FAR *dest, BYTE FAR *source, int count)
{

    register int i;

    for (i = 0; i < count; i++)
	*dest++ = *source++;
}	

/* dialog box support variables and functions */
static int bytesizeindex;
static int parityindex;
static int commportindex;
static BOOL NEAR SetCommValues(HWND hDlg);
static void NEAR InitCommParams(HWND hDlg);
static WORD GetBaudRateID(WORD rate);

/* dialog box handler to set communications parameters */
BOOL FAR PASCAL SetCommParams(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{

    int result;

    switch (message) {
	case WM_INITDIALOG:
	    InitCommParams(hDlg);
	    break;

	case WM_COMMAND:
	    switch (wParam) {

		case IDD_BAUDRATE:
		    if (HIWORD(lParam) == EN_CHANGE) {
    			result = GetDlgItemInt(hDlg,IDD_BAUDRATE, 
						(LONG)NULL, FALSE);
			CheckRadioButton(hDlg, IDD_110, IDD_OTHER,
						GetBaudRateID(result));
		    }
		    break;
			
		case IDOK:
		    result = SetCommValues(hDlg);
		    if (result)
		        EndDialog(hDlg, TRUE);
		    break;
		
		case IDCANCEL:
		    EndDialog(hDlg, FALSE);
		    break;

		case IDD_COM1:
		case IDD_COM2:
		    CheckRadioButton(hDlg, IDD_COM1, IDD_COM2, wParam);
		    commportindex = wParam;
		    break;

		case IDD_7BIT:
		case IDD_8BIT:
		    CheckRadioButton(hDlg, IDD_7BIT, IDD_8BIT, wParam);
		    bytesizeindex = wParam;
		    break;

		case IDD_NONE:
		case IDD_ODD:
		case IDD_EVEN:
		case IDD_MARK:
		case IDD_SPACE:
		    parityindex = wParam;
		    CheckRadioButton(hDlg, IDD_NONE, IDD_SPACE, wParam);
		    break;

		case IDD_110:
		case IDD_150:
		case IDD_300:
		case IDD_600:
		case IDD_1200:
		case IDD_1800:
		case IDD_2000:
		case IDD_2400:
		case IDD_3600:
		case IDD_4800:
		case IDD_7200:
		case IDD_9600:
		case IDD_19200:
		    SetDlgItemInt(hDlg, IDD_BAUDRATE, 
					BaudRateTable[wParam - IDD_110], FALSE);
		    break;
		case IDD_OTHER:
		    CheckRadioButton(hDlg, IDD_110, IDD_OTHER, wParam);
		    SetFocus(GetDlgItem(hDlg,IDD_BAUDRATE));
		    break;

		case IDD_SAVE:
		case IDD_DEFPORT:
		    if (IsDlgButtonChecked(hDlg, wParam))
			CheckDlgButton(hDlg, wParam, FALSE);
		    else
			CheckDlgButton(hDlg, wParam, TRUE);
	  	    break;

		default:
		    return FALSE;
	    }
	    break;

	default:
	    return FALSE;
    }
    return TRUE;
}

/* set DCB */
static BOOL NEAR SetCommValues(HWND hDlg)
{

    int result;
    WORD oldbaud;
    BYTE oldstop;
    BYTE oldparity;
    BYTE oldbytesize;
    BYTE newport, oldport;
    char comstr[10];
    short newcid;
    char wintitle[WINTITLELEN];
        
    oldbaud = CommData.BaudRate;
    oldbytesize = CommData.ByteSize;
    oldparity = CommData.Parity;
    oldstop = CommData.StopBits;
    oldport = CommData.Id;
    
    newport = (BYTE)(commportindex - IDD_COM1);
    if (newport != oldport) {
        LoadString(hInst, IDS_COM1 + newport, (LPSTR)comstr, sizeof(comstr));
	newcid = OpenComm((LPSTR)comstr, RXQUESIZE, TXQUESIZE);
	if (newcid >= 0) {
	    CloseCommPort(hDlg, &cid);
	    if (cid == INT_MIN) {
		cid = newcid;
	        CommData.Id = (BYTE)cid;
	        LoadString(hInst,IDS_WINTITLE,(LPSTR)wintitle,sizeof(wintitle));
		strcat(wintitle,comstr);
		SetWindowText(MW.hWnd, (LPSTR)wintitle);				
	    }
	    else {
		CloseCommPort(hDlg, &newcid);
	        ShowMessage(hDlg, IDS_CANNOTCHANGEPORT);
		return FALSE;
	    }
	}
	else {
	    ShowMessage(hDlg, IDS_CANNOTCHANGEPORT);
	    return FALSE;
	}
    }

    CommData.BaudRate = GetDlgItemInt(hDlg,IDD_BAUDRATE, (LONG)NULL, FALSE);
    CommData.ByteSize = (BYTE)(bytesizeindex - IDD_7BIT + 7);
    CommData.Parity = (BYTE)(parityindex - IDD_NONE);
    if (CommData.BaudRate <= 110)
	CommData.StopBits = TWOSTOPBITS;
    else
	CommData.StopBits = ONESTOPBIT;

    result = SetCommState((DCB FAR *)&CommData);

    if (result == 0) {
	if (IsDlgButtonChecked(hDlg, IDD_SAVE))
	    SaveCommParams();
    	if (IsDlgButtonChecked(hDlg, IDD_DEFPORT))
	    SetDefaultPort();
	return TRUE;
    }
    else {
	CommData.BaudRate = oldbaud;
	CommData.ByteSize = oldbytesize;
	CommData.Parity = oldparity;
	CommData.StopBits = oldstop;
	SetCommState((DCB FAR *)&CommData);
	InitCommParams(hDlg);
        ShowMessage(hDlg, IDS_NOCOMSET);
	return FALSE;
    }
}

/* set up a default port */
static void NEAR SetDefaultPort()
{
    char keystr[10];
    char valstr[10];
    int val1, val2;

    if (commportindex == IDD_COM1) {
	val1 = IDS_COM1;
	val2 = IDS_COM2;
    }
    else {
	val1 = IDS_COM2;
	val2 = IDS_COM1;
    }
    
    LoadString(hInst, IDS_FIRSTPORT, (LPSTR)keystr, sizeof(keystr));
    LoadString(hInst, val1, (LPSTR)valstr, sizeof(valstr));
    WriteProfileString((LPSTR)szAppName,(LPSTR)keystr,(LPSTR)valstr);
    LoadString(hInst, IDS_SECONDPORT, (LPSTR)keystr, sizeof(keystr));
    LoadString(hInst, val2, (LPSTR)valstr, sizeof(valstr));
    WriteProfileString((LPSTR)szAppName,(LPSTR)keystr,(LPSTR)valstr);

    BroadcastWinIniChange();
}

/* save parameters to win.ini */
static void NEAR SaveCommParams()
{
    char keystr[10];
    char valstr[30];
    int portval;

    S401.BaudRate = CommData.BaudRate;
    S401.ByteSize = CommData.ByteSize;
    S401.Parity = CommData.Parity;
    S401.StopBits = CommData.StopBits;

    portval = commportindex - IDD_COM1;
    LoadString(hInst, IDS_COM1 + portval, (LPSTR)keystr, sizeof(keystr));
    itoa(CommData.BaudRate, valstr, 10);

    switch (CommData.Parity) {
	case EVENPARITY:
	    strcat(valstr, ",e");
	    break;
	case ODDPARITY:
	    strcat(valstr, ",o");
	    break;
	default:
	    strcat(valstr, ",n");
	    break;
    }

    if (CommData.ByteSize == 8)
	strcat(valstr, ",8");
    else
        strcat(valstr, ",7");

    if (CommData.BaudRate <= 110)
	strcat(valstr, ",2");
    else
	strcat(valstr, ",1");

    WriteProfileString((LPSTR)szAppName,(LPSTR)keystr,(LPSTR)valstr);

    BroadcastWinIniChange();
}

/* initialize comm parameters */
static void NEAR InitCommParams(HWND hDlg)
{

    parityindex = IDD_NONE + CommData.Parity;
    bytesizeindex = IDD_7BIT + CommData.ByteSize - 7;
    commportindex = IDD_COM1 + CommData.Id;

    SetDlgItemInt(hDlg, IDD_BAUDRATE, CommData.BaudRate, FALSE);
    CheckRadioButton(hDlg, IDD_NONE, IDD_SPACE, parityindex);
    CheckRadioButton(hDlg, IDD_7BIT, IDD_8BIT, bytesizeindex);
    CheckRadioButton(hDlg, IDD_COM1, IDD_COM2, commportindex);
}

/* read baud rate from table */
static WORD GetBaudRateID(WORD rate)
{

    register int i;
    register WORD id;

    id = IDD_OTHER;

    for (i = 0; i < BAUDTABLESIZE; i++) {
	if (rate == BaudRateTable[i]) {
	    id = IDD_110 + i;	
	    break;
	}
    }
    return id;
}

/* dialog box for setting terminal parameters */
BOOL FAR PASCAL SetTermParams(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{

    switch (message) {
	case WM_INITDIALOG:
	    TermParamInit(hDlg);
	    break;

	case WM_COMMAND:
	    switch (wParam) {
		case IDOK:
		    TermParamSet(hDlg);
		    EndDialog(hDlg, TRUE);
		    break;
		
		case IDCANCEL:
		    EndDialog(hDlg, FALSE);
		    break;

		case IDD_WRAP:
		case IDD_LFCR:
		case IDD_CRLF:
		case IDD_SAVE:
		    if (IsDlgButtonChecked(hDlg, wParam))
			CheckDlgButton(hDlg, wParam, FALSE);
		    else
			CheckDlgButton(hDlg, wParam, TRUE);
	  	    break;

		case IDD_LINE:
		case IDD_BLOCK:
		    CheckRadioButton(hDlg, IDD_LINE, IDD_BLOCK, wParam);
		    break;

		case IDD_HALF:
		case IDD_FULL:
		    CheckRadioButton(hDlg, IDD_HALF, IDD_FULL, wParam);
		    break;

		case IDD_HEATH:
		case IDD_ANSI:
		    CheckRadioButton(hDlg, IDD_HEATH, IDD_ANSI, wParam);
		    break;

		case IDD_NORMAL:
		case IDD_SHIFTED:
		    CheckRadioButton(hDlg, IDD_NORMAL, IDD_SHIFTED, wParam);
		    break;

		default:
		    return FALSE;
	    }
	    break;

	default:
	    return FALSE;
    }
    return TRUE;
}

/* dialog box initialization */
static void NEAR TermParamInit(HWND hDlg)
{

    CheckRadioButton(hDlg, IDD_HALF, IDD_FULL, IDD_HALF + CD.FullDuplex);
    CheckRadioButton(hDlg, IDD_HEATH, IDD_ANSI, IDD_HEATH + CD.ANSIMode);
    CheckRadioButton(hDlg,IDD_NORMAL,IDD_SHIFTED,IDD_NORMAL + CD.ShiftedKeypad);
    CheckRadioButton(hDlg, IDD_LINE, IDD_BLOCK,IDD_LINE + CD.BlockCursor);
    CheckDlgButton(hDlg, IDD_WRAP, CD.WrapAround);
    CheckDlgButton(hDlg, IDD_CRLF, CD.CRonLF);
    CheckDlgButton(hDlg, IDD_LFCR, CD.LFonCR);
}

/* set terminal parameters */
static void NEAR TermParamSet(HWND hDlg)
{

    int *ptr, *ptr1;
    int i, index;
    char szValStr[30], szKeyStr[30];

    for (i = IDD_HALF; i <= IDD_FULL; i++)
	if (SendDlgItemMessage(hDlg,i,BM_GETCHECK,0,0L)) {
	    CD.FullDuplex = i - IDD_HALF;
	    break;
	}

    for (i = IDD_HEATH; i <= IDD_ANSI; i++)
	if (SendDlgItemMessage(hDlg,i,BM_GETCHECK,0,0L)) {
	    CD.ANSIMode = i - IDD_HEATH;
	    break;
	}

    for (i = IDD_NORMAL; i <= IDD_SHIFTED; i++)
	if (SendDlgItemMessage(hDlg,i,BM_GETCHECK,0,0L)) {
	    CD.ShiftedKeypad = i - IDD_NORMAL;
	    break;
	}

    for (i = IDD_LINE; i <= IDD_BLOCK; i++)
	if (SendDlgItemMessage(hDlg,i,BM_GETCHECK,0,0L)) {
	    index = i - IDD_LINE;
	    break;
	}

    if (index != CD.BlockCursor)
	if (index)
	    ProcessSetCommand(4);
	else
	    ProcessResetCommand(4);
 
    CD.WrapAround = IsDlgButtonChecked(hDlg, IDD_WRAP);
    CD.LFonCR = IsDlgButtonChecked(hDlg, IDD_LFCR);
    CD.CRonLF = IsDlgButtonChecked(hDlg, IDD_CRLF);

    if (IsDlgButtonChecked(hDlg, IDD_SAVE)) {
	ptr = &S402.BlockCursor;
        ptr1 = &CD.BlockCursor;
        for (i = 0; i < 8; i++) {
            itoa(*ptr1,szValStr,sizeof(szValStr));
	    *ptr++ = *ptr1++;
            LoadString(hInst,IDS_BLOCKCURSOR+i,(LPSTR)szKeyStr,
				sizeof(szKeyStr));
	    WriteProfileString((LPSTR)szAppName,(LPSTR)szKeyStr,
			(LPSTR)szValStr);
	}
	BroadcastWinIniChange();
    }
}

/* dialog box function to edit function key strings */
BOOL FAR PASCAL SetStringParams(hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{

    register int i;

    switch (message) {
	case WM_INITDIALOG:
	    CheckRadioButton(hDlg, IDD_F1, IDD_F12, IDD_F1);
	    CheckRadioButton(hDlg,IDD_NOSHIFT,IDD_CTRLSHIFT,IDD_SHIFT);
    	    SendDlgItemMessage(hDlg,IDD_STRINGEDIT,EM_LIMITTEXT,80,0L);
	    StringOp(hDlg, IDOK+1);
	    break;

	case WM_COMMAND:
	    switch (wParam) {
		case IDD_F1:
		case IDD_F2:
		case IDD_F3:
		case IDD_F4:
		case IDD_F5:
		case IDD_F6:
		case IDD_F7:
		case IDD_F8:
		case IDD_F9:
		case IDD_F10:
		case IDD_F11:
		case IDD_F12:
		    CheckRadioButton(hDlg, IDD_F1, IDD_F12, wParam);
		    StringOp(hDlg, wParam);
		    break;

		case IDD_NOSHIFT:
		    CheckRadioButton(hDlg, IDD_F1, IDD_F12, IDD_F10);
		    CheckRadioButton(hDlg, IDD_NOSHIFT, IDD_CTRLSHIFT, wParam);
		    for (i = IDD_F1; i < IDD_F12; i++) {
			if (i >= IDD_F10)
			    continue;
			else
			    EnableWindow(GetDlgItem(hDlg, i), FALSE);
		    }
		    StringOp(hDlg, wParam);
		    break;

		case IDD_SHIFT:
		case IDD_CONTROL:
		case IDD_CTRLSHIFT:
		    CheckRadioButton(hDlg, IDD_NOSHIFT, IDD_CTRLSHIFT, wParam);
		    for (i = IDD_F1; i < IDD_F12; i++) {
			if (i == IDD_F6)
			    continue;
			else
			    EnableWindow(GetDlgItem(hDlg, i), TRUE);
		    }
		    StringOp(hDlg, wParam);
		    break;

		case IDOK:
		    StringOp(hDlg, wParam);
		    break;

		case IDCANCEL:
		    EndDialog(hDlg, FALSE);
		    break;

		default:
		    return FALSE;
	    }
	    break;

	default:
	    return FALSE;
    }
    return TRUE;
}

/* support function for function key edit dialog box */
static void NEAR StringOp(HWND hDlg, WORD param)
{

    register int index, i;
    char fstring[80];
    char *ptr;

    for (i = IDD_F1; i <= IDD_F12; i++)
	if (SendDlgItemMessage(hDlg,i,BM_GETCHECK,0,0L)) {
	    index = i - IDD_F1;
	    break;
	}
    
    for (i = IDD_NOSHIFT; i <= IDD_CTRLSHIFT; i++)
	if (SendDlgItemMessage(hDlg,i,BM_GETCHECK,0,0L)) {
	    switch (i) {
		case IDD_NOSHIFT:
		    ptr = szFKey[index];
		    break;
		case IDD_SHIFT:
		    ptr = szSFKey[index];
		    break;
		case IDD_CONTROL:
		    ptr = szCFKey[index];
		    break;
		case IDD_CTRLSHIFT:
		    ptr = szCSFKey[index];
		    break;
	    }
	    break;
    }
    if (param == IDOK) {
        GetDlgItemText(hDlg, IDD_STRINGEDIT, (LPSTR)fstring, 80);
        WriteProfileString((LPSTR)szAppName,(LPSTR)ptr,(LPSTR)fstring);
	BroadcastWinIniChange();
        SetDlgItemText(hDlg,IDD_STRINGEDIT,(LPSTR)fstring);	    
    }
    else {
        GetProfileString((LPSTR)szAppName,
			 (LPSTR)ptr,(LPSTR)"",(LPSTR)fstring,80);
        SetDlgItemText(hDlg,IDD_STRINGEDIT,(LPSTR)fstring);	    
        SendDlgItemMessage(hDlg,IDD_STRINGEDIT,EM_SETSEL,0,MAKELONG(0,32767));
    }
/*    SetFocus(GetDlgItem(hDlg,IDD_STRINGEDIT));   */
}
