Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1975 lines
52 KiB

/* File: D:\wacker\emu\minitel.c (Created: 05-Mar-1994)
*
* Copyright 1994, 1998 by Hilgraeve Inc. -- Monroe, MI
* All rights reserved
*
* $Revision: 12 $
* $Date: 7/12/02 1:25p $
*/
#include <windows.h>
#pragma hdrstop
#include <time.h>
#include <tdll\stdtyp.h>
#include <tdll\tdll.h>
#include <tdll\session.h>
#include <tdll\cloop.h>
#include <tdll\print.h>
#include <tdll\capture.h>
#include <tdll\assert.h>
#include <tdll\mc.h>
#include <tdll\update.h>
#include <tdll\chars.h>
#include <tdll\cnct.h>
#include <tdll\term.h>
#include <tdll\backscrl.h>
#include <tdll\htchar.h>
#include <term\res.h>
#include <tapi.h>
#include <cncttapi\cncttapi.hh>
#include "emu.h"
#include "emu.hh"
#include "emuid.h"
#include "minitel.hh"
#include "keytbls.h"
#if defined(INCL_MINITEL)
static void emuMinitelRedisplayLine(const HHEMU hhEmu,
const int row,
const int col);
static int minitel_kbdin(const HHEMU hhEmu, int key, const int fTest);
static ECHAR minitelMapMosaics(const HHEMU hhEmu, ECHAR ch);
static void minitelFullScrnReveal(const HHEMU hhEmu);
static void minitelFullScrnConceal(const HHEMU hhEmu);
static void minitelSS2(const HHEMU hhEmu);
static void minitelSS2Part2(const HHEMU hhEmu);
static void minitelInsMode(const HHEMU hhEmu);
static void minitelPRO1(const HHEMU hhEmu);
static void minitelPRO2Part1(const HHEMU hhEmu);
static void minitelPRO2Part2(const HHEMU hhEmu);
static void minitelStatusReply(const HHEMU hhEmu);
/*
Here begins the famed and fabled Minitel emulator. Abandon all hope
all ye who..., well you get the idea. The Minitel emulator uses a
combination of character attributes and field attributes. See the
book "minitel 1B" for description of field attributes. Page numbers
referenced in this code refer to the before mentioned book. - mrw
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* emuMinitelInit
*
* DESCRIPTION:
* Startup routine for the minitel emulator.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void emuMinitelInit(const HHEMU hhEmu)
{
int i;
LOGFONT lf;
HWND hwndTerm;
PSTMTPRIVATE pstPRI;
static struct trans_entry const minitel_tbl[] =
{
{NEW_STATE, 0, 0, 0}, // 0
{0, ETEXT('\x00'), ETEXT('\x01'), nothing},
{0, ETEXT('\x20'), ETEXT('\x7F'), minitelGraphic},
{1, ETEXT('\x1B'), ETEXT('\x1B'), nothing},
{0, ETEXT('\x07'), ETEXT('\x07'), emu_bell},
{0, ETEXT('\b'), ETEXT('\b'), minitelBackspace},
{0, ETEXT('\t'), ETEXT('\t'), minitelHorzTab},
{0, ETEXT('\n'), ETEXT('\n'), minitelLinefeed},
{0, ETEXT('\x0B'), ETEXT('\x0B'), minitelVerticalTab},
{0, ETEXT('\x0C'), ETEXT('\x0C'), minitelFormFeed},
{0, ETEXT('\r'), ETEXT('\r'), carriagereturn},
{0, ETEXT('\x0E'), ETEXT('\x0F'), minitelCharSet}, // change char set
{0, ETEXT('\x11'), ETEXT('\x11'), minitelCursorOn}, // cursor on
{5, ETEXT('\x12'), ETEXT('\x12'), nothing}, // repeat
{12,ETEXT('\x13'), ETEXT('\x13'), nothing}, // SEP
{0, ETEXT('\x14'), ETEXT('\x14'), minitelCursorOff},// cursor off
{20,ETEXT('\x16'), ETEXT('\x16'), nothing}, // SS2 (undocumented)
{0, ETEXT('\x18'), ETEXT('\x18'), minitelCancel}, // cancel
{20,ETEXT('\x19'), ETEXT('\x19'), nothing}, // SS2
{0, ETEXT('\x1C'), ETEXT('\x1C'), nothing}, // really is nothing.
{13,ETEXT('\x1D'), ETEXT('\x1D'), nothing}, // SS3,X ingnored, p99, 1.2.7
{0, ETEXT('\x1E'), ETEXT('\x1E'), minitelRecordSeparator},
{3, ETEXT('\x1F'), ETEXT('\x1F'), nothing}, // Unit Seperator
//{0, ETEXT('\x7F'), ETEXT('\x7F'), minitelDel},
{NEW_STATE, 0, 0, 0}, // 1 - seen ESC
{1, ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x01'), ETEXT('\x1F'), minitelResync},
{18,ETEXT('\x23'), ETEXT('\x23'), nothing},
{14,ETEXT('\x25'), ETEXT('\x25'), nothing},
{13,ETEXT('\x35'), ETEXT('\x37'), nothing}, // eat ESC,35-37,X sequences
{6, ETEXT('\x39'), ETEXT('\x39'), nothing}, // PROT1, p134
{7, ETEXT('\x3A'), ETEXT('\x3A'), nothing}, // PROT2, p134
{8, ETEXT('\x3B'), ETEXT('\x3B'), nothing}, // PROT3, p134
{2, ETEXT('\x5B'), ETEXT('\x5B'), ANSI_Pn_Clr},
{0, ETEXT('\x40'), ETEXT('\x49'), emuMinitelCharAttr}, // forground color, flashing
{0, ETEXT('\x4C'), ETEXT('\x4F'), emuMinitelCharAttr}, // char width & height
{0, ETEXT('\x50'), ETEXT('\x5A'), emuMinitelFieldAttr},// background, underlining
{0, ETEXT('\x5F'), ETEXT('\x5F'), emuMinitelFieldAttr},// reveal display
{0, ETEXT('\x5C'), ETEXT('\x5D'), emuMinitelCharAttr}, // inverse
{0, ETEXT('\x61'), ETEXT('\x61'), minitelCursorReport},
{22,ETEXT('\x20'), ETEXT('\x2F'), nothing}, // p.99 ISO 2022
{NEW_STATE, 0, 0, 0}, // 2 - seen ESC [
{2, ETEXT('\x00'), ETEXT('\x00'), nothing},
{2, ETEXT('\x30'), ETEXT('\x39'), ANSI_Pn},
{2, ETEXT('\x3B'), ETEXT('\x3B'), ANSI_Pn_End},
{2, ETEXT('\x3A'), ETEXT('\x3F'), ANSI_Pn},
{0, ETEXT('\x40'), ETEXT('\x40'), minitelInsChars},
{0, ETEXT('\x41'), ETEXT('\x41'), minitelCursorUp},
{0, ETEXT('\x42'), ETEXT('\x42'), ANSI_CUD},
{0, ETEXT('\x43'), ETEXT('\x43'), ANSI_CUF},
{0, ETEXT('\x44'), ETEXT('\x44'), ANSI_CUB},
{0, ETEXT('\x48'), ETEXT('\x48'), minitelCursorDirect},
{0, ETEXT('\x4A'), ETEXT('\x4A'), minitelClrScrn},
{0, ETEXT('\x4B'), ETEXT('\x4B'), minitelClrLn},
{0, ETEXT('\x4C'), ETEXT('\x4C'), minitelInsRows},
{0, ETEXT('\x4D'), ETEXT('\x4D'), minitelDelRows},
{0, ETEXT('\x50'), ETEXT('\x50'), minitelDelChars},
{0, ETEXT('\x68'), ETEXT('\x69'), minitelInsMode},
{0, ETEXT('\x7A'), ETEXT('\x7B'), nothing}, //* p144 12.2
{0, ETEXT('\x7D'), ETEXT('\x7D'), nothing}, //* p144 12.2
{0, ETEXT('\x7F'), ETEXT('\x7F'), minitelResetTerminal}, //* p145, 13.2
{NEW_STATE, 0, 0, 0}, // 3 - unit separtor character position
{3, ETEXT('\x00'), ETEXT('\x00'), nothing},
{4, ETEXT('\x01'), ETEXT('\xFF'), minitelUSRow},
{NEW_STATE, 0, 0, 0}, // 4 - end of unit separtor character position
{4, ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x01'), ETEXT('\xFF'), minitelUSCol},
{NEW_STATE, 0, 0, 0}, // 5 - number of repeats
{5, ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x40'), ETEXT('\x7F'), minitelRepeat},
{0, ETEXT('\x00'), ETEXT('\xFF'), minitelResync},
{NEW_STATE, 0, 0, 0}, // 6 - Protocol 1 sequence (PRO1,X)
{6, ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x01'), ETEXT('\xFF'), minitelPRO1},
{NEW_STATE, 0, 0, 0}, // 7 - Protocol 2 sequence (PRO2,X,Y)
{7, ETEXT('\x00'), ETEXT('\x00'), nothing},
{8, ETEXT('\x01'), ETEXT('\xFF'), minitelPRO2Part1},
{NEW_STATE, 0, 0, 0}, // 8 - Protocol 2 sequence (PRO2,X,Y)
{8, ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x01'), ETEXT('\xFF'), minitelPRO2Part2},
{NEW_STATE, 0, 0, 0}, // 9 - Protocol 3 sequence (PRO3,X,Y,Z)
{9, ETEXT('\x00'), ETEXT('\x00'), nothing},
{10,ETEXT('\x01'), ETEXT('\xFF'), nothing},
{NEW_STATE, 0, 0, 0}, // 10 - Protocol 3 sequence (PRO3,X,Y,Z)
{10,ETEXT('\x00'), ETEXT('\x00'), nothing},
{11,ETEXT('\x01'), ETEXT('\xFF'), nothing},
{NEW_STATE, 0, 0, 0}, // 11 - Protocol 3 sequence (PRO3,X,Y,Z)
{11,ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x01'), ETEXT('\xFF'), nothing},
{NEW_STATE, 0, 0, 0}, // 12 - SEP
{12,ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x01'), ETEXT('\xFF'), nothing},
{NEW_STATE, 0, 0, 0}, // 13 - ESC,35-39,X sequences eaten, p99, 1.2.7
{13,ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x01'), ETEXT('\xFF'), nothing},
{NEW_STATE, 0, 0, 0}, // 14 - screen transparency mode
{15,ETEXT('\x1B'), ETEXT('\x1B'), nothing},
{14,ETEXT('\x00'), ETEXT('\xFF'), nothing},
{23,ETEXT('\x20'), ETEXT('\x2F'), nothing}, // could be ISO 2022
{NEW_STATE, 0, 0, 0}, // 15 - screen transparency mode continued, seen ESC
{16,ETEXT('\x25'), ETEXT('\x25'), nothing},
{17,ETEXT('\x2F'), ETEXT('\x2F'), nothing},
{15,ETEXT('\x00'), ETEXT('\x00'), nothing},
{14,ETEXT('\x00'), ETEXT('\xFF'), nothing},
{NEW_STATE, 0, 0, 0}, // 16 - screen transparency mode continued, seen ESC \x25
{0, ETEXT('\x40'), ETEXT('\x40'), nothing},
{16,ETEXT('\x00'), ETEXT('\x00'), nothing},
{14,ETEXT('\x00'), ETEXT('\xFF'), nothing},
{NEW_STATE, 0, 0, 0}, // 17 - screen transparency mode continued, seen ESC \x2F
{0, ETEXT('\x3F'), ETEXT('\x3F'), nothing},
{17,ETEXT('\x00'), ETEXT('\x00'), nothing},
{14,ETEXT('\x00'), ETEXT('\xFF'), nothing},
{NEW_STATE, 0, 0, 0}, // 18 - Full screen reveal/hide, seen ESC \x23
{18,ETEXT('\x00'), ETEXT('\x00'), nothing},
{19,ETEXT('\x20'), ETEXT('\x20'), nothing},
{23,ETEXT('\x20'), ETEXT('\x2F'), nothing}, // could be ISO 2022
{NEW_STATE, 0, 0, 0}, // 19 - Full screen reveal/hide, seen ESC \x23 \x20
{19,ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x58'), ETEXT('\x58'), minitelFullScrnConceal},
{0, ETEXT('\x5F'), ETEXT('\x5F'), minitelFullScrnReveal},
{NEW_STATE, 0, 0, 0}, // 20 - SS2
{20,ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x00'), ETEXT('\x1F'), minitelResync},
{21,ETEXT('\x20'), ETEXT('\x7F'), minitelSS2}, // valid SS2
{NEW_STATE, 0, 0, 0}, // 21 - SS2 part 2
{21,ETEXT('\x00'), ETEXT('\x00'), nothing},
{0, ETEXT('\x20'), ETEXT('\x7F'), minitelSS2Part2}, // valid SS2
{NEW_STATE, 0, 0, 0}, // 22 - p.99 ISO 2022
{23,ETEXT('\x20'), ETEXT('\x2F'), nothing},
{0, ETEXT('\x00'), ETEXT('\x1F'), minitelResync},
{NEW_STATE, 0, 0, 0}, // 23 - p.99 ISO 2022
{24,ETEXT('\x20'), ETEXT('\x2F'), nothing},
{0, ETEXT('\x00'), ETEXT('\x1F'), minitelResync},
{NEW_STATE, 0, 0, 0}, // 24 - p.99 ISO 2022
{25, ETEXT('\x30'), ETEXT('\x3F'), nothing}, // page 107.
{0, ETEXT('\x30'), ETEXT('\x7E'), nothing}, // final character
{0, ETEXT('\x00'), ETEXT('\x1F'), minitelResync},
{NEW_STATE, 0, 0, 0}, // 25 - p.99 ISO 2022
{0, ETEXT('\x0D'), ETEXT('\x0D'), nothing}, // page 107. eat CR
{0, ETEXT('\x00'), ETEXT('\x7F'), minitelResync},
};
if (hhEmu == 0)
{
assert(0);
return;
}
emuInstallStateTable(hhEmu, minitel_tbl, DIM(minitel_tbl));
// Allocate and initialize private data for Minitel emulator.
//
if (hhEmu->pvPrivate != 0)
{
free(hhEmu->pvPrivate);
hhEmu->pvPrivate = 0;
}
hhEmu->pvPrivate = malloc(sizeof(MTPRIVATE));
if (hhEmu->pvPrivate == 0)
{
assert(FALSE);
return;
}
pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
memset(pstPRI, 0, sizeof(MTPRIVATE));
pstPRI->minitel_last_char = ETEXT(' ');
/* load key array */
emuKeyTableLoad(hhEmu, Minitel_KeyTable,
sizeof(Minitel_KeyTable)/sizeof(KEYTBLSTORAGE),
&hhEmu->stEmuKeyTbl);
/* --- Allocate attribute buffer for Minitel junk --- */
pstPRI->apstMT = malloc(MAX_EMUROWS * sizeof(PSTMINITEL));
if (pstPRI->apstMT == 0)
{
assert(FALSE);
return;
}
memset(pstPRI->apstMT, 0, MAX_EMUROWS * sizeof(PSTMINITEL));
for (i = 0 ; i < MAX_EMUROWS ; ++i)
{
pstPRI->apstMT[i] = malloc(MAX_EMUCOLS * sizeof(STMINITEL));
if (pstPRI->apstMT[i] == 0)
{
assert(FALSE);
return;
}
memset(pstPRI->apstMT[i], 0, MAX_EMUCOLS * sizeof(STMINITEL));
}
/* --- Setup defaults --- */
hhEmu->emu_maxrow = 24; // 25 line emulator
hhEmu->emu_maxcol = 39; // start in 40 column mode
hhEmu->top_margin = 1; // access to row 0 is restricted.
hhEmu->bottom_margin = hhEmu->emu_maxrow; // this has to equal emu_maxrow which changed
hhEmu->emu_kbdin = minitel_kbdin;
hhEmu->emu_graphic = minitelGraphic;
hhEmu->emu_deinstall = emuMinitelDeinstall;
hhEmu->emu_ntfy = minitelNtfy;
hhEmu->emuHomeHostCursor = minitelHomeHostCursor;
#ifdef INCL_TERMINAL_SIZE_AND_COLORS
hhEmu->emu_setscrsize = emuMinitelSetScrSize;
#endif
hhEmu->emu_highchar = (TCHAR)0xFF;
if (hhEmu->emu_currow == 0)
(*hhEmu->emu_setcurpos)(hhEmu, 1, hhEmu->emu_curcol - 1);
// Also, set font to Arial Alternative
//
memset(&lf, 0, sizeof(LOGFONT));
hwndTerm = sessQueryHwndTerminal(hhEmu->hSession);
termGetLogFont(hwndTerm, &lf);
if (StrCharCmpi(lf.lfFaceName, "Arial Alternative") != 0)
{
StrCharCopyN(lf.lfFaceName, "Arial Alternative", LF_FACESIZE);
lf.lfWeight = FW_DONTCARE;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
lf.lfStrikeOut = FALSE;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
lf.lfQuality = DEFAULT_QUALITY;
lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
termSetLogFont(hwndTerm, &lf);
}
// Backscroll not supported in minitel
//
backscrlSetUNumLines(sessQueryBackscrlHdl(hhEmu->hSession), 0);
// Initialize colors for the Minitel.
//
std_setcolors(hhEmu, VC_BRT_WHITE, VC_BLACK);
// Set terminal to power-up state
//
minitelResetTerminal(hhEmu);
// Turn backscroll off for Minitel
//
backscrlSetShowFlag(sessQueryBackscrlHdl(hhEmu->hSession), FALSE);
// Enable Minitel toolbar buttons
//
PostMessage(sessQueryHwnd(hhEmu->hSession), WM_SESS_SHOW_SIDEBAR, 0, 0);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* emuMinitelDeinstall
*
* DESCRIPTION:
* Frees the extra attribute buffer needed to manage serial attributes.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void emuMinitelDeinstall(const HHEMU hhEmu)
{
int i;
PSTMTPRIVATE pstPRI;
assert(hhEmu);
pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
if (pstPRI)
{
if (pstPRI->apstMT)
{
for (i = 0 ; i < MAX_EMUROWS ; ++i)
{
if (pstPRI->apstMT[i])
{
free(pstPRI->apstMT[i]);
pstPRI->apstMT[i] = NULL;
}
}
free(pstPRI->apstMT);
pstPRI->apstMT = 0;
}
free(hhEmu->pvPrivate);
hhEmu->pvPrivate = 0;
}
// Hide Minitel toolbar buttons
//
ShowWindow(sessQuerySidebarHwnd(hhEmu->hSession), SW_HIDE);
//
// Make sure to free the key table that was created when the emulator
// was loaded, otherwise there is a memory leak. REV: 05/09/2001
//
emuKeyTableFree(&hhEmu->stEmuKeyTbl);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelReset
*
* DESCRIPTION:
* Sets emulator to an initial state. Used for record and unit
* separators.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void minitelReset(const HHEMU hhEmu)
{
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
pstPRI->minitelG1Active = FALSE;
memset(&hhEmu->emu_charattr, 0, sizeof(hhEmu->emu_charattr));
hhEmu->emu_charattr.txtclr = VC_BRT_WHITE;
hhEmu->emu_charattr.bkclr = VC_BLACK;
pstPRI->apstMT[hhEmu->emu_imgrow][hhEmu->emu_curcol].isattr = 0;
memset(&pstPRI->stLatentAttr, 0, sizeof(pstPRI->stLatentAttr));
pstPRI->stLatentAttr.fBkClr = TRUE;
hhEmu->attrState[CS_STATE] =
hhEmu->attrState[CSCLEAR_STATE] = hhEmu->emu_charattr;
hhEmu->emu_clearattr = hhEmu->emu_charattr;
minitelNtfy(hhEmu, 0);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelGraphic
*
* DESCRIPTION:
* Handles displayable characters.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void minitelGraphic(const HHEMU hhEmu)
{
ECHAR ccode;
ECHAR aechBuf[10];
int r;
int row = hhEmu->emu_currow;
int col = hhEmu->emu_curcol;
BOOL fRedisplay = FALSE;
BOOL fDblHi;
STATTR stAttr;
ECHAR *tp = hhEmu->emu_apText[hhEmu->emu_imgrow];
const PSTATTR ap = hhEmu->emu_apAttr[hhEmu->emu_imgrow];
const HUPDATE hUpdate = sessQueryUpdateHdl(hhEmu->hSession);
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
ccode = hhEmu->emu_code;
if (ccode == 0)
return;
pstPRI->minitel_last_char = ccode;
if (hhEmu->mode_IRM == SET)
{
if (col < hhEmu->emu_maxcol)
{
memmove(&tp[col+1], &tp[col],
(unsigned)(hhEmu->emu_maxcol-col) * sizeof(ECHAR));
memmove(&ap[col+1], &ap[col],
(unsigned)(hhEmu->emu_maxcol-col) * sizeof(STATTR));
memmove(&pstPRI->apstMT[hhEmu->emu_imgrow][col+1],
&pstPRI->apstMT[hhEmu->emu_imgrow][col],
(unsigned)(hhEmu->emu_maxcol-col) * sizeof(STMINITEL));
}
}
/* --- check if we are overwriting an attribute space --- */
if (pstPRI->apstMT[hhEmu->emu_imgrow][col].isattr)
{
pstPRI->apstMT[hhEmu->emu_imgrow][col].isattr = FALSE;
fRedisplay = TRUE;
}
/* --- If we receive a space and have latent attributes, validate --- */
if (ccode == ETEXT('\x20') && pstPRI->stLatentAttr.fModified
&& pstPRI->minitelG1Active == FALSE)
{
r = hhEmu->emu_imgrow;
// Color
//
pstPRI->apstMT[r][col].fbkclr = pstPRI->stLatentAttr.fBkClr;
pstPRI->apstMT[r][col].bkclr = pstPRI->stLatentAttr.bkclr;
// Conceal
//
pstPRI->apstMT[r][col].conceal = pstPRI->stLatentAttr.conceal;
// Underline
//
pstPRI->apstMT[r][col].undrln = pstPRI->stLatentAttr.undrln;
pstPRI->apstMT[hhEmu->emu_imgrow][col].isattr = TRUE;
// This is truely wierd. We don't reset the fBkclr, fConceal, or
// fUndrln fields, only the fModified flag. Thus if any serial
// attributes are set, all latent values get updated. The only
// guy who appears to be able to turn off an attribute is the
// mosaic character which validates the background color and sets
// the fBkClr flag to false. I can't think of a reason why it
// should work this way. - mrw
//
pstPRI->stLatentAttr.fModified = FALSE;
fRedisplay = TRUE;
}
/* --- If we switched to G1, map char to location in new font --- */
if (pstPRI->minitelG1Active)
ccode = minitelMapMosaics(hhEmu, ccode);
pstPRI->apstMT[hhEmu->emu_imgrow][col].ismosaic =
(unsigned)pstPRI->minitelG1Active;
/* --- If we switched to semigraphic mode, validate the background --- */
if (pstPRI->minitelG1Active)
{
// Guess what? Latent background color is always adopted for mosaics.
// This is a major undocumented find. Basicly, mosaics
// (semigraphics) always use the latent background color regardless
// of the validation state.
//
ap[col].bkclr = pstPRI->stLatentAttr.bkclr;
fRedisplay = TRUE;
// Something tricky here. Reception of a mosaic validates the
// background color. Validate means adopt the color. It also
// means that if we shift back to the alpha (G0 char set) and
// recieve a space, we DON'T validate the background color a
// second time. So we keep a seperate flag for the background
// color validation. - mrw
//
pstPRI->stLatentAttr.fBkClr = FALSE;
}
/* --- Normal character processing --- */
tp[col] = ccode;
// Update the end of row index if necessary.
//
if (col > hhEmu->emu_aiEnd[hhEmu->emu_imgrow])
hhEmu->emu_aiEnd[hhEmu->emu_imgrow] = col;
/* --- Find out this characters current attributes and adjust --- */
stAttr = GetAttr(hhEmu, row, col);
ap[col] = hhEmu->emu_charattr;
ap[col].bkclr = stAttr.bkclr;
ap[col].blank = stAttr.blank;
ap[col].undrln = stAttr.undrln;
if (pstPRI->minitelG1Active)
ap[col].symbol = 1;
// Documented: 0x7F (mosaic or alpha) always maps to 0x5F in the G1
// character set (solid block).
//
if (tp[col] == ETEXT('\x7F'))
{
tp[col] = ETEXT('\x5F');
ap[col].symbol = 1;
}
/* --- Double high stuff --- */
if (hhEmu->emu_charattr.dblhilo)
{
if (row >= 2)
{
r = row_index(hhEmu, row-1);
hhEmu->emu_apText[r][col] = ccode;
hhEmu->emu_apAttr[r][col] = ap[col];
hhEmu->emu_apAttr[r][col].dblhilo = 0;
hhEmu->emu_apAttr[r][col].dblhihi = 1;
pstPRI->apstMT[r][col] = pstPRI->apstMT[hhEmu->emu_imgrow][col];
updateChar(hUpdate, row-1, col, col);
}
}
/* --- Double wide stuff --- */
if (hhEmu->emu_charattr.dblwilf)
{
if (row > 0 && col < hhEmu->emu_maxcol)
{
tp[col+1] = ccode;
ap[col+1] = ap[col];
ap[col+1].dblwilf = 0;
ap[col+1].dblwirt = 1;
// Major league bug.
//
pstPRI->apstMT[hhEmu->emu_imgrow][col+1] =
pstPRI->apstMT[hhEmu->emu_imgrow][col];
}
if (hhEmu->emu_charattr.dblhilo)
{
r = row_index(hhEmu, row-1);
hhEmu->emu_apText[r][col+1] = ccode;
hhEmu->emu_apAttr[r][col+1] = ap[col];
hhEmu->emu_apAttr[r][col+1].dblwilf = 0;
hhEmu->emu_apAttr[r][col+1].dblwirt = 1;
hhEmu->emu_apAttr[r][col+1].dblhilo = 0;
hhEmu->emu_apAttr[r][col+1].dblhihi = 1;
pstPRI->apstMT[r][col+1] = pstPRI->apstMT[hhEmu->emu_imgrow][col];
}
}
/* --- Need to use old row and column --- */
if (fRedisplay)
emuMinitelRedisplayLine(hhEmu, row, col);
/* --- Need to bump the column guy an extra notch if double wide --- */
if (hhEmu->emu_charattr.dblwilf)
{
col += 1;
hhEmu->emu_aiEnd[hhEmu->emu_imgrow] = col;
}
updateChar(hUpdate, row, hhEmu->emu_curcol, col);
/* --- bump column position, check for wrap, etc. --- */
if (++col > hhEmu->emu_maxcol)
{
// Escape code 0x18 is referred to as cancel in the minitel doco.
// It fills from the cursor pos to the end of the row with blanks.
// Note: Also, it does not force wrap in anyway since
// the cursor position is not updated. That's why we have to
// check here. - mrw:5/3/95
//
if (pstPRI->fInCancel || row == 0)
{
col = hhEmu->emu_maxcol;
return;
}
printEchoString(hhEmu->hPrintEcho, tp,
emuRowLen(hhEmu, hhEmu->emu_imgrow));
CnvrtMBCStoECHAR(aechBuf, sizeof(aechBuf), TEXT("\r\n"),
StrCharGetByteCount(TEXT("\r\n")));
printEchoString(hhEmu->hPrintEcho, aechBuf, sizeof(ECHAR) * 2);
CaptureLine(sessQueryCaptureFileHdl(hhEmu->hSession), CF_CAP_LINES,
tp, emuRowLen(hhEmu, hhEmu->emu_imgrow));
// Wrap around accounts for double high
//
fDblHi = (BOOL)hhEmu->emu_charattr.dblhilo;
if (row == hhEmu->bottom_margin)
{
if (pstPRI->fScrollMode)
minitel_scrollup(hhEmu, fDblHi ? 2 : 1);
else
row = fDblHi ? 2 : 1;
}
else if (row != 0)
{
row += fDblHi ? 2 : 1;
if (row > hhEmu->emu_maxrow)
row = 2;
}
col = 0;
}
// Finally, set the cursor position. This will reset emu_currow
// and emu_curcol.
//
(*hhEmu->emu_setcurpos)(hhEmu, row, col);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* emuMinitelRedisplayLine
*
* DESCRIPTION:
* The trick to field attributes is when you encounter one, you need to
* update the rest of the line that follows since changing or overwriting
* an attribute space affects stuff to the right.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
* int row - row to redisplay
* int col - start column
*
* RETURNS:
* void
*
*/
static void emuMinitelRedisplayLine(const HHEMU hhEmu,
const int row,
const int col)
{
int i = row_index(hhEmu, row);
int fDblHi = FALSE;
const ECHAR *tp = hhEmu->emu_apText[i];
const PSTATTR ap = hhEmu->emu_apAttr[i];
const PSTATTR apl = hhEmu->emu_apAttr[row_index(hhEmu, row-1)];
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
const PSTMINITEL pstMT = pstPRI->apstMT[i];
for (i = col ; i <= hhEmu->emu_maxcol ; ++i)
{
ap[i] = GetAttr(hhEmu, row, i);
// Here's a wierd one. Attribute spaces (as opposed to plain spaces)
// validate but do not display the underline attribute. I suspect
// something similar with seperated mosaics. - mrw
if (tp[i] == ETEXT('\x20') && pstMT[i].isattr)
ap[i].undrln = 0;
// If we're redisplaying a row that has a double hi character,
// then we have to redisplay the upper-half as well.
if (ap[i].dblhilo)
{
fDblHi = TRUE;
apl[i] = GetAttr(hhEmu, row-1, i);
}
}
if (fDblHi)
{
updateChar(sessQueryUpdateHdl(hhEmu->hSession),
row-1, col, hhEmu->emu_maxcol);
}
updateChar(sessQueryUpdateHdl(hhEmu->hSession),
row, col, hhEmu->emu_maxcol);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* GetAttr
*
* DESCRIPTION:
* Walks the current row and builds a composite attribute based on
* the encountered attribute spaces.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
* iRow - logical row
* iCol - logical col
*
* RETURNS:
* composite attribute.
*
*/
STATTR GetAttr(const HHEMU hhEmu, const int iRow, const int iCol)
{
int i;
STATTR stAttr;
const int r = row_index(hhEmu, iRow);
const PSTATTR ap = hhEmu->emu_apAttr[r];
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
const PSTMINITEL pstMT = pstPRI->apstMT[r];
stAttr = hhEmu->emu_apAttr[r][iCol];
stAttr.bkclr = 0;
stAttr.undrln = 0;
stAttr.blank = 0;
for (i = 0 ; i <= iCol ; ++i)
{
// Mosaics validate the background color. Do it first however,
// because an attribute space can change it to something else.
if (pstMT[i].ismosaic)
stAttr.bkclr = ap[i].bkclr;
if (pstMT[i].isattr)
{
if (pstMT[i].fbkclr)
stAttr.bkclr = pstMT[i].bkclr;
stAttr.undrln = pstMT[i].undrln;
stAttr.blank = pstMT[i].conceal;
}
// Mosaics always cancel underlining.
//
if (pstMT[i].ismosaic)
stAttr.undrln = 0;
}
return stAttr;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* emuMinitelCharAttr
*
* DESCRIPTION:
* Modifies the current character attribute. Does not affect field
* attributes.
*
* mrw - 11/1/94: Went to high intensity colors to more closely match
* the minitel colors.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void emuMinitelCharAttr(const HHEMU hhEmu)
{
STATTR stAttr = hhEmu->attrState[CS_STATE];
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
switch (hhEmu->emu_code)
{
case ETEXT('\x40'): stAttr.txtclr = 0; break;
case ETEXT('\x41'): stAttr.txtclr = 12; /*4*/ break;
case ETEXT('\x42'): stAttr.txtclr = 10; /*2*/ break;
case ETEXT('\x43'): stAttr.txtclr = 14; /*6*/ break;
case ETEXT('\x44'): stAttr.txtclr = 9; /*1*/ break;
case ETEXT('\x45'): stAttr.txtclr = 13; /*5*/ break;
case ETEXT('\x46'): stAttr.txtclr = 11; /*3*/ break;
case ETEXT('\x47'): stAttr.txtclr = 15; break;
case ETEXT('\x48'): stAttr.blink = 1; break;
case ETEXT('\x49'): stAttr.blink = 0; break;
case ETEXT('\x4C'): // normal size
if (pstPRI->minitelG1Active)
return;
stAttr.dblhilo = 0;
stAttr.dblwilf = 0;
break;
case ETEXT('\x4D'): // double height
if (pstPRI->minitelG1Active || hhEmu->emu_currow <= 1)
return;
stAttr.dblhilo= 1;
stAttr.dblwilf = 0;
break;
case ETEXT('\x4E'): // double width
if (pstPRI->minitelG1Active || hhEmu->emu_currow < 1)
return;
stAttr.dblhilo = 0;
stAttr.dblwilf = 1;
break;
case ETEXT('\x4F'): // double size
if (pstPRI->minitelG1Active || hhEmu->emu_currow <= 1)
return;
stAttr.dblhilo = 1;
stAttr.dblwilf = 1;
break;
case ETEXT(ETEXT('\x5C')): // normal polarity
if (pstPRI->minitelG1Active)
return;
stAttr.revvid = 0;
break;
case ETEXT(ETEXT('\x5D')): // reverse polarity
if (pstPRI->minitelG1Active)
return;
stAttr.revvid = 1;
break;
default:
break;
}
/* --- commit changes --- */
hhEmu->emu_charattr =
hhEmu->attrState[CS_STATE] =
hhEmu->attrState[CSCLEAR_STATE] = stAttr;
hhEmu->attrState[CSCLEAR_STATE].revvid = 0;
hhEmu->attrState[CSCLEAR_STATE].undrln = 0;
hhEmu->emu_clearattr = hhEmu->attrState[CSCLEAR_STATE];
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* emuMinitelFieldAttr
*
* DESCRIPTION:
* Dreaded field attributes. Actually, this routine updates what is
* called a Latent Attribute. The attributes only become effective
* when a space is recieved.
*
* mrw - 11/1/94: Went to high intensity colors to more closely match
* the minitel colors.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void emuMinitelFieldAttr(const HHEMU hhEmu)
{
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
LATENTATTR * const pstLA = &pstPRI->stLatentAttr;
switch (hhEmu->emu_code)
{
case ETEXT('\x50'): pstLA->bkclr = 0; break;
case ETEXT('\x51'): pstLA->bkclr = 12; break;
case ETEXT('\x52'): pstLA->bkclr = 10; break;
case ETEXT('\x53'): pstLA->bkclr = 14; break;
case ETEXT('\x54'): pstLA->bkclr = 9; break;
case ETEXT('\x55'): pstLA->bkclr = 13; break;
case ETEXT('\x56'): pstLA->bkclr = 11; break;
case ETEXT('\x57'): pstLA->bkclr = 15; break;
case ETEXT('\x58'): pstLA->conceal=1; break;
case ETEXT('\x5F'): pstLA->conceal=0; break;
case ETEXT('\x59'): // separated mosaics off
if (pstPRI->minitelG1Active)
{
pstPRI->minitelUseSeparatedMosaics = 0;
return;
}
else
{
pstPRI->stLatentAttr.undrln = 0;
}
break;
case ETEXT('\x5A'): // separated mosaics on
if (pstPRI->minitelG1Active)
{
pstPRI->minitelUseSeparatedMosaics = 1;
return;
}
else
{
pstPRI->stLatentAttr.undrln = 1;
}
break;
default:
return;
}
// Undocumented: setting any field attribute invalidates the
// latent color context.
//
pstPRI->stLatentAttr.fBkClr = TRUE;
pstPRI->stLatentAttr.fModified = TRUE;
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
* minitel_kbdin
*
* DESCRIPTION:
* Processes keys for the minitel emulator.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
* key - key to process
*
* RETURNS:
* nothing
*/
static int minitel_kbdin(const HHEMU hhEmu, int key, const int fTest)
{
int index;
TCHAR c;
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
if ((index = emuKbdKeyLookup(hhEmu, key, &hhEmu->stEmuKeyTbl)) != -1)
{
if (!fTest)
{
emuSendKeyString(hhEmu, index, &hhEmu->stEmuKeyTbl);
// This completes the code sent by emuSendKeyString(), page 124
//
if (key == (VK_RIGHT | VIRTUAL_KEY | SHIFT_KEY) ||
key == (VK_RIGHT | VIRTUAL_KEY | SHIFT_KEY | EXTENDED_KEY))
{
c = (pstPRI->minitelSecondDep) ? TEXT('\x6c') : TEXT('\x68');
CLoopCharOut(sessQueryCLoopHdl(hhEmu->hSession), c);
}
// Check for disconnect key. If hit twice consecutively,
// it posts a disconnect to the modem guy.
//
if (key == (VK_F9 | VIRTUAL_KEY))
{
pstPRI->F9 += 1;
if (pstPRI->F9 == 2)
{
PostMessage(sessQueryHwnd(hhEmu->hSession),
WM_DISCONNECT, 0, 0);
pstPRI->F9 = 0;
}
}
}
}
else
{
// reset F9 counter, must have two consecutive to disconnect
//
pstPRI->F9 = 0;
index = std_kbdin(hhEmu, key, fTest);
}
return index;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelCharSet
*
* DESCRIPTION:
* We don't really switch character sets here. Since minitel uses
* 7 bit ASCII, we can user the half of the ASCII table for the
* contigous and seperated mosaics that comprise the G1 char set.
* Other rule here is that switching the the G1 character set
* validates the background color on reception of the first mosaic.
* One thing I haven't figured out yet is when a field attribute is
* validated, does the latent attribute get reset or retain the last color?
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void minitelCharSet(const HHEMU hhEmu)
{
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
pstPRI->stLatentAttr.undrln = 0;
if (hhEmu->emu_code == ETEXT(0x0E)) // switch to G1
{
pstPRI->minitelG1Active = TRUE;
pstPRI->minitelUseSeparatedMosaics = FALSE;
}
else
{
pstPRI->minitelG1Active = FALSE;
}
// underline, size and polarity attributes permanently canceled.
//
hhEmu->emu_charattr.undrln = 0;
hhEmu->emu_charattr.dblhihi = 0;
hhEmu->emu_charattr.dblhilo = 0;
hhEmu->emu_charattr.dblwilf = 0;
hhEmu->emu_charattr.dblwirt = 0;
hhEmu->emu_charattr.revvid = 0;
hhEmu->emu_charattr.symbol = 0;
hhEmu->attrState[CS_STATE] =
hhEmu->attrState[CSCLEAR_STATE] = hhEmu->emu_charattr;
hhEmu->emu_clearattr = hhEmu->emu_charattr;
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelResetTerminal
*
* DESCRIPTION:
* Response to a 1B 39 7F sequence. Puts terminal in power-up state.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void minitelResetTerminal(const HHEMU hhEmu)
{
minitelClearScreen(hhEmu, 0); // clear screen
(*hhEmu->emu_setcurpos)(hhEmu, 0, 0);
minitelClearLine(hhEmu, 0); // clear line 0
(*hhEmu->emu_setcurpos)(hhEmu, 1, 0);
minitelReset(hhEmu); // reset attributes
((PSTMTPRIVATE)hhEmu->pvPrivate)->fScrollMode = 0;
EmuStdSetCursorType(hhEmu, EMU_CURSOR_NONE);
minitelNtfy(hhEmu, 0);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelCursorOn
*
* DESCRIPTION:
* Turns minitel cursor on.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void minitelCursorOn(const HHEMU hhEmu)
{
EmuStdSetCursorType(hhEmu, EMU_CURSOR_BLOCK);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelCursorOff
*
* DESCRIPTION:
* Turns minitel cursor off
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void minitelCursorOff(const HHEMU hhEmu)
{
#if defined(NDEBUG)
EmuStdSetCursorType(hhEmu, EMU_CURSOR_NONE);
#else
EmuStdSetCursorType(hhEmu, EMU_CURSOR_BLOCK);
#endif
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* mintelMapMosaics
*
* DESCRIPTION:
* Maps regular character to a mosaic char for our font only.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
* ch - character to convert
*
* RETURNS:
* converted or original character.
*
*/
static ECHAR minitelMapMosaics(const HHEMU hhEmu, ECHAR ch)
{
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
if (ch >= ETEXT('\x21') && ch <= ETEXT('\x3F'))
ch += ETEXT('\x1F');
// Another weird undocumented affect. Columns 4 and 5 (except 5F)
// map to columns 6 and 7 (page 101)
//
else if (ch >= ETEXT('\x40') && ch <= ETEXT('\x5E'))
ch += ETEXT('\x20');
else if (ch >= ETEXT('\x60') && ch <= ETEXT('\x7E'))
ch += 0;
if (pstPRI->minitelUseSeparatedMosaics && ch >= ETEXT('\x21') &&
ch <= ETEXT('\x7F'))
{
ch += ETEXT('\x40');
}
return ch;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelCursorReport
*
* DESCRIPTION:
* Return the current cursor location as US row col.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void minitelCursorReport(const HHEMU hhEmu)
{
TCHAR ach[40];
ECHAR aech[40];
wsprintf(ach, TEXT("US%c%c"), hhEmu->emu_currow, hhEmu->emu_curcol);
CnvrtMBCStoECHAR(aech, sizeof(aech), ach,
StrCharGetByteCount(ach) + sizeof(TCHAR));
emuSendString(hhEmu, aech, StrCharGetEcharByteCount(aech));
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelFullScrnConceal
*
* DESCRIPTION:
* Just sets the blank bits on all the attributes.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
static void minitelFullScrnConceal(const HHEMU hhEmu)
{
int i, j;
PSTATTR ap;
for (i = 1 ; i <= hhEmu->emu_maxrow ; ++i)
{
ap = hhEmu->emu_apAttr[row_index(hhEmu, i)];
for (j = 0 ; j <= hhEmu->emu_maxcol ; ++j, ++ap)
ap->blank = 1;
updateLine(sessQueryUpdateHdl(hhEmu->hSession),
1, hhEmu->emu_maxrow);
}
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelFullScrnReveal
*
* DESCRIPTION:
* Just sets the blank bits on all the attributes.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
static void minitelFullScrnReveal(const HHEMU hhEmu)
{
int i, j;
PSTATTR ap;
for (i = 1 ; i <= hhEmu->emu_maxrow ; ++i)
{
ap = hhEmu->emu_apAttr[row_index(hhEmu, i)];
for (j = 0 ; j <= hhEmu->emu_maxcol ; ++j, ++ap)
ap->blank = 0;
}
updateLine(sessQueryUpdateHdl(hhEmu->hSession), 1, hhEmu->emu_maxrow);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelResync
*
* DESCRIPTION:
* Certain codes will cause the emulator to resynchronize, (goto state
* zero) and play the character thru.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
void minitelResync(const HHEMU hhEmu)
{
hhEmu->state = 0;
#if defined(EXTENDED_FEATURES)
(void)(*hhEmu->emu_datain)(hhEmu, hhEmu->emu_code);
#else
(void)(*hhEmu->emu_datain)((HEMU)hhEmu, hhEmu->emu_code);
#endif
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelSS2
*
* DESCRIPTION:
* SS2 is an alternate character set. It only has about 15 symbols so
* we just map them here to ones in our current minitel font.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
static void minitelSS2(const HHEMU hhEmu)
{
const int row = hhEmu->emu_currow;
const int col = hhEmu->emu_curcol;
BOOL fNoAdvance = FALSE;
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
/* --- SS2 codes are ignored in semigraphic mode --- */
if (pstPRI->minitelG1Active)
{
hhEmu->state = 0;
return;
}
/* --- Map the character --- */
switch (hhEmu->emu_code)
{
case ETEXT('\x23'): hhEmu->emu_code = ETEXT('\xA3'); break; // british pound
case ETEXT('\x24'): hhEmu->emu_code = ETEXT('\x24'); break; // Dollar sign
case ETEXT('\x26'): hhEmu->emu_code = ETEXT('\x23'); break; // pound sign
case ETEXT('\x27'): hhEmu->emu_code = ETEXT('\xA7'); break; // integral
case ETEXT('\x2C'): hhEmu->emu_code = ETEXT('\xC3'); break; // left arrow
case ETEXT('\x2D'): hhEmu->emu_code = ETEXT('\xC0'); break; // up arrow
case ETEXT('\x2E'): hhEmu->emu_code = ETEXT('\xC4'); break; // right arrow
case ETEXT('\x2F'): hhEmu->emu_code = ETEXT('\xC5'); break; // down arrow
case ETEXT('\x30'): hhEmu->emu_code = ETEXT('\xB0'); break; // degree
case ETEXT('\x31'): hhEmu->emu_code = ETEXT('\xB1'); break; // plus-minus
case ETEXT('\x38'): hhEmu->emu_code = ETEXT('\xF7'); break; // divide
case ETEXT('\x3C'): hhEmu->emu_code = ETEXT('\xBC'); break; // 1/4
case ETEXT('\x3D'): hhEmu->emu_code = ETEXT('\xBD'); break; // 1/2
case ETEXT('\x3E'): hhEmu->emu_code = ETEXT('\xBE'); break; // 3/4
case ETEXT('\x41'): hhEmu->emu_code = ETEXT('\x60'); fNoAdvance = TRUE; break;
case ETEXT('\x42'): hhEmu->emu_code = ETEXT('\xB4'); fNoAdvance = TRUE; break;
case ETEXT('\x43'): hhEmu->emu_code = ETEXT('\x5E'); fNoAdvance = TRUE; break;
case ETEXT('\x48'): hhEmu->emu_code = ETEXT('\xA8'); fNoAdvance = TRUE; break;
case ETEXT('\x4A'): hhEmu->emu_code = ETEXT('\xB8'); fNoAdvance = TRUE; break;
case ETEXT('\x4B'): hhEmu->emu_code = ETEXT('\xB8'); fNoAdvance = TRUE; break;
case ETEXT('\x6A'): hhEmu->emu_code = ETEXT('\x8C'); break;
case ETEXT('\x7A'): hhEmu->emu_code = ETEXT('\x9C'); break;
case ETEXT('\x7B'): hhEmu->emu_code = ETEXT('\xDF'); break;
default: hhEmu->emu_code = ETEXT('\x5F'); break;
}
minitelGraphic(hhEmu);
if (fNoAdvance)
{
(*hhEmu->emu_setcurpos)(hhEmu, row, col); // don't advance cursor
}
else
{
// If we don't advance the cursor, we're done with this SS2
// sequence and reset the state to 0 - mrw, 2/3/95
//
hhEmu->state = 0;
}
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelSS2Part2
*
* DESCRIPTION:
* The second half a an SS2 code is the vowel portion for the accents
* page 90.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
static void minitelSS2Part2(const HHEMU hhEmu)
{
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
switch (hhEmu->emu_code)
{
case ETEXT('a'):
switch (pstPRI->minitel_last_char)
{
case ETEXT('\x60'): hhEmu->emu_code = ETEXT('\xE0'); break;
case ETEXT('\x5E'): hhEmu->emu_code = ETEXT('\xE2'); break;
case ETEXT('\xA8'): hhEmu->emu_code = ETEXT('\xE4'); break;
default: break;
}
break;
case ETEXT('e'):
switch (pstPRI->minitel_last_char)
{
case ETEXT('\x60'): hhEmu->emu_code = ETEXT('\xE8'); break;
case ETEXT('\xB4'): hhEmu->emu_code = ETEXT('\xE9'); break;
case ETEXT('\x5E'): hhEmu->emu_code = ETEXT('\xEA'); break;
case ETEXT('\xA8'): hhEmu->emu_code = ETEXT('\xEB'); break;
default: break;
}
break;
case ETEXT('i'):
switch (pstPRI->minitel_last_char)
{
case ETEXT('\x5E'): hhEmu->emu_code = ETEXT('\xEE'); break;
case ETEXT('\xA8'): hhEmu->emu_code = ETEXT('\xEF'); break;
default: break;
}
break;
case ETEXT('o'):
switch (pstPRI->minitel_last_char)
{
case ETEXT('\x5E'): hhEmu->emu_code = ETEXT('\xF4'); break;
case ETEXT('\xA8'): hhEmu->emu_code = ETEXT('\xF6'); break;
default: break;
}
break;
case ETEXT('u'):
switch (pstPRI->minitel_last_char)
{
case ETEXT('\x60'): hhEmu->emu_code = ETEXT('\xF9'); break;
case ETEXT('\x5E'): hhEmu->emu_code = ETEXT('\xFB'); break;
case ETEXT('\xA8'): hhEmu->emu_code = ETEXT('\xFC'); break;
default: break;
}
break;
case ETEXT('c'):
switch (pstPRI->minitel_last_char)
{
case ETEXT('\xB8'): hhEmu->emu_code = ETEXT('\xE7'); break;
default: break;
}
break;
default:
// Docs say if we're not one of the above chars, then overwrite
// position with current char.
break;
}
minitelGraphic(hhEmu);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelInsMode
*
* DESCRIPTION:
* Sets or Resets the insert mode depending on received code.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
static void minitelInsMode(const HHEMU hhEmu)
{
hhEmu->mode_IRM = (hhEmu->emu_code == ETEXT('\x68')) ? SET : RESET;
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelNtfy
*
* DESCRIPTION:
* Paints an inverted F or C when connection/disconnection notifications
* come in.
*
* ARGUMENTS:
* hhEmuPass - change this to hhEmu when reentrancy done.
* nNtfyCode - why it was called, (we don't use)
*
* RETURNS:
* void
*
*/
void minitelNtfy(const HHEMU hhEmu, const int nNtfyCode)
{
const int r = row_index(hhEmu, 0);
const int c = hhEmu->emu_maxcol - 1;
ECHAR chr;
BOOL fFlash = FALSE;
switch (cnctQueryStatus(sessQueryCnctHdl(hhEmu->hSession)))
{
case CNCT_STATUS_FALSE:
default:
chr = ETEXT('F');
break;
case CNCT_STATUS_TRUE:
chr = ETEXT('C');
break;
case CNCT_STATUS_CONNECTING:
chr = ETEXT('C');
fFlash = TRUE;
break;
}
hhEmu->emu_apText[r][c] = chr;
hhEmu->emu_apAttr[r][c].revvid = 1;
hhEmu->emu_apAttr[r][c].blink = (unsigned)fFlash;
hhEmu->emu_apAttr[r][c].symbol = 0; // mrw-5/5/95
hhEmu->emu_aiEnd[r] = c;
updateChar(sessQueryUpdateHdl(hhEmu->hSession), 0, c, c);
NotifyClient(hhEmu->hSession, EVENT_TERM_UPDATE, 0);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelPRO1
*
* DESCRIPTION:
* Handles PRO1 sequences (ESC,39,X).
*
* ARGUMENTS:
* hhEmu - private emulator handle
*
* RETURNS:
* void
*
*/
static void minitelPRO1(const HHEMU hhEmu)
{
ECHAR aechBuf[35];
static const TCHAR achID[] = TEXT("\x01\x43r0\x04");
switch (hhEmu->emu_code)
{
case ETEXT('\x7B'): // ENQROM (page 139)
// See pages 21 & 22. Basicly we send back an indentification
// sequence delimited by SOH and EOT
//
CnvrtMBCStoECHAR(aechBuf, sizeof(aechBuf), achID,
StrCharGetByteCount(achID));
CLoopSend(sessQueryCLoopHdl(hhEmu->hSession), aechBuf, 5, 0);
break;
case ETEXT('\x67'): // Disconnect (page 139)
PostMessage(sessQueryHwnd(hhEmu->hSession), WM_DISCONNECT, 0, 0);
break;
case ETEXT('\x72'):
minitelStatusReply(hhEmu);
break;
default:
break;
}
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelPRO2Part1
*
* DESCRIPTION:
* Handles first half of a PRO2 sequence.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
*/
static void minitelPRO2Part1(const HHEMU hhEmu)
{
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
pstPRI->minitel_PRO1 = hhEmu->emu_code;
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelPRO2Part2
*
* DESCRIPTION:
* Handles the second half of a PRO2 sequence.
*
* ARGUMENTS:
* hhEmu - private emulator handle
*
* RETURNS:
* void
*
*/
static void minitelPRO2Part2(const HHEMU hhEmu)
{
int fUpperCase;
BYTE abKey[256];
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
switch (hhEmu->emu_code)
{
case ETEXT('\x43'): // scrolling
if (pstPRI->minitel_PRO1 == ETEXT('\x69'))
{
pstPRI->fScrollMode = TRUE;
}
if (pstPRI->minitel_PRO1 == ETEXT('\x6A'))
{
pstPRI->fScrollMode = FALSE;
}
minitelStatusReply(hhEmu);
break;
case ETEXT('\x44'): // error correction procedure (not implemented)
break;
case ETEXT('\x45'): // keyboard upper/lower case
if (pstPRI->minitel_PRO1 == ETEXT('\x69'))
{
fUpperCase = FALSE;
}
else if (pstPRI->minitel_PRO1 == ETEXT('\x6A'))
{
fUpperCase = TRUE;
}
else
{
break;
}
if (GetKeyboardState(abKey))
{
if (fUpperCase)
{
abKey[VK_CAPITAL] |= 0x01;
}
else
{
abKey[VK_CAPITAL] &= 0xfe;
}
SetKeyboardState(abKey);
}
#if TODO // TODO:REV 3/1/2002 Set the CapLock key state when GetKeyboardState fails.
else
{
SHORT lCapitalKeyState = GetKeyState(VK_CAPITAL);
if (fUpperCase)
{
lCapitalKeyState |= 0x01;
}
else
{
lCapitalKeyState &= 0xfe;
}
if (lCapitalKeyState)
{
INPUT lInput;
lInput.ki =
SendInput(1, lInput, sizeof(INPUT));
}
}
#endif // TODO:REV 3/1/2002
minitelStatusReply(hhEmu);
break;
default:
break;
}
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* minitelStatusReply
*
* DESCRIPTION:
* Acknowledgement sequence for some PRO2 sequences and status requests.
*
* ARGUMENTS:
* hhEmu - private emulator handle.
*
* RETURNS:
* void
*
* AUTHOR: Mike Ward, 08-May-1995
*/
static void minitelStatusReply(const HHEMU hhEmu)
{
ECHAR ach[10];
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
// The PRO2 sequences \x43 and \x45 all return and acknowledgement
// of the form PRO2,\x73,status byte. The format of the status byte
// is defined in page 143, section 11.2.
//
// strcpy(ach, "\x1b\x3A\x73");
CnvrtMBCStoECHAR(ach, sizeof(ach), TEXT("\x1b\x3A\x73"),
StrCharGetByteCount(TEXT("\x1b\x3A\x73")));
ach[3] = ETEXT('\x40'); // bit 7 is always 1.
ach[3] |= pstPRI->fScrollMode ? ETEXT('\x02') : ETEXT('\x00');
ach[3] |=(GetKeyState(VK_CAPITAL) > 0) ? ETEXT('\x00') : ETEXT('\x08');
ach[4] = ETEXT('\0');
CLoopSend(sessQueryCLoopHdl(hhEmu->hSession), ach, 4, 0);
return;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* emuMinitelSendKey
*
* DESCRIPTION:
* Used by the toolbar to emit the correct minitel sequence for the
* specified button.
*
* ARGUMENTS:
* hEmu - public emulator handle.
* iCmd - command string to send.
*
* RETURNS:
* void
*
* AUTHOR: Mike Ward, 10-Mar-1995
*/
void emuMinitelSendKey(const HEMU hEmu, const int iCmd)
{
TCHAR *pach;
ECHAR aechBuf[20];
const HHEMU hhEmu = (HHEMU)hEmu;
const PSTMTPRIVATE pstPRI = (PSTMTPRIVATE)hhEmu->pvPrivate;
HCNCT hCnct = NULL;
BOOL bSendKey = TRUE;
int iRet = 0;
switch (iCmd)
{
case IDM_MINITEL_INDEX: pach = TEXT("\x13") TEXT("F"); break;
case IDM_MINITEL_CANCEL: pach = TEXT("\x13") TEXT("E"); break;
case IDM_MINITEL_PREVIOUS: pach = TEXT("\x13") TEXT("B"); break;
case IDM_MINITEL_REPEAT: pach = TEXT("\x13") TEXT("C"); break;
case IDM_MINITEL_GUIDE: pach = TEXT("\x13") TEXT("D"); break;
case IDM_MINITEL_CORRECT: pach = TEXT("\x13") TEXT("G"); break;
case IDM_MINITEL_NEXT: pach = TEXT("\x13") TEXT("H"); break;
case IDM_MINITEL_SEND: pach = TEXT("\x13") TEXT("A"); break;
case IDM_MINITEL_CONFIN:
pach = TEXT("\x13") TEXT("I");
pstPRI->F9 += 1;
break;
default:
assert(0);
return;
}
//
// Attempt to make a connection if we are currently disconnected, and
// we are supposed to initiate a connection.
//
hCnct = sessQueryCnctHdl(hhEmu->hSession);
iRet = cnctQueryStatus(hCnct);
if (iCmd == IDM_MINITEL_CONFIN)
{
if (iRet != CNCT_STATUS_TRUE && iRet != CNCT_STATUS_CONNECTING &&
iRet != CNCT_STATUS_DISCONNECTING)
{
if (SendMessageTimeout(sessQueryHwnd(hhEmu->hSession), WM_COMMAND,
IDM_ACTIONS_DIAL, 0,
SMTO_ABORTIFHUNG, 1000, NULL) == 0)
{
DWORD dwSendKey = GetLastError();
bSendKey = FALSE;
}
else
{
hCnct = sessQueryCnctHdl(hhEmu->hSession);
if (!hCnct)
{
bSendKey = FALSE;
}
else
{
iRet = cnctQueryStatus(hCnct);
if (iRet != CNCT_STATUS_TRUE)
{
bSendKey = FALSE;
}
}
}
}
else if(iRet != CNCT_STATUS_DISCONNECTING)
{
PostMessage(sessQueryHwnd(hhEmu->hSession), WM_DISCONNECT, 0, 0);
pstPRI->F9 = 0;
bSendKey = FALSE;
}
}
else if (iRet != CNCT_STATUS_TRUE)
{
bSendKey = FALSE;
}
if (bSendKey == TRUE)
{
CnvrtMBCStoECHAR(aechBuf, sizeof(aechBuf), pach,
StrCharGetByteCount(pach) + sizeof(TCHAR));
emuSendString((HHEMU)hEmu, aechBuf, StrCharGetEcharByteCount(aechBuf));
}
return;
}
#ifdef INCL_TERMINAL_SIZE_AND_COLORS
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* FUNCTION:
* emuMinitelSetScrSize
*
* DESCRIPTION:
* Replaces std_setscrsize which was added to allow user settable screen
* sizes. However, the Minitel doesn't allow this.
*
* ARGUMENTS:
* hhEmu - The internal emulator handle.
*
* RETURNS:
* void
*
* AUTHOR: Bob Everett - 1 Sep 1998
*/
void emuMinitelSetScrSize(const HHEMU hhEmu)
{
}
#endif
#endif // INCL_MINITEL