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