|
|
/* 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
|