123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801 |
- { This file is part of fpterm - a terminal emulator, written in Free Pascal
- Copyright (C) 2022, 2024 Nikolay Nikolov <[email protected]>
- This library is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published by
- the Free Software Foundation; either version 2 of the License, or (at your
- option) any later version with the following modification:
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent modules,and
- to copy and distribute the resulting executable under terms of your choice,
- provided that you also meet, for each linked independent module, the terms
- and conditions of the license of that module. An independent module is a
- module which is not derived from or based on this library. If you modify
- this library, you may extend this exception to your version of the library,
- but you are not obligated to do so. If you do not wish to do so, delete this
- exception statement from your version.
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
- for more details.
- You should have received a copy of the GNU Library General Public License
- along with this library; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.
- }
- unit FpTerm.Controller;
- {$mode objfpc}{$H+}
- interface
- uses
- FpTerm.Base, FpTerm.Model, FpTerm.Logger;
- type
- TTerminalStateMachineState = (
- tsmsInitial,
- tsmsESC,
- tsmsESC_SP,
- tsmsESC_Hash, { ESC # }
- tsmsESC_Percent,
- tsmsCSI,
- tsmsOSC,
- tsmsOSC_ESC,
- tsmsDCS,
- tsmsDCS_ESC,
- tsmsDesignateG0123CharacterSet94,
- tsmsDesignateG0123CharacterSet94_Percent,
- tsmsDesignateG0123CharacterSet94_Quote,
- tsmsDesignateG0123CharacterSet94_Ampersand,
- tsmsDesignateG0123CharacterSet96,
- tsmsUTF8_1ByteLeft,
- tsmsUTF8_2BytesLeft,
- tsmsUTF8_3BytesLeft,
- tsmsVT52_Initial,
- tsmsVT52_ESC,
- tsmsVT52_ESC_Y,
- tsmsVT52_ESC_Y_Ps
- );
- TTerminalModeFlag = (
- tmfCursorKeysSendApplicationSequences,
- tmfAutoNewLine,
- tmfAutoWrapMode,
- tmfBracketedPasteMode,
- tmfSend8BitC1Controls,
- tmfAllow80To132ModeSwitching,
- tmfInsertMode,
- tmfOriginMode,
- tmfSendReceiveMode,
- tmfKeyboardActionMode,
- tmfReverseVideo,
- tmfUTF8Mode
- );
- TTerminalModeFlags = set of TTerminalModeFlag;
- TTerminalMouseTrackingMode = (
- tmtmNone,
- tmtmX10,
- tmtmNormal,
- tmtmHighlight,
- tmtmButtonEvent,
- tmtmAnyEvent
- );
- TTerminalMouseProtocolEncoding = (
- tmpeX10,
- tmpeUTF8,
- tmpeSGR,
- tmpeURXVT,
- tmpeSGRPixels
- );
- TTerminalType = (
- ttVT52,
- ttVT100,
- ttVT101,
- ttVT102,
- ttVT125,
- ttVT131,
- ttVT132,
- ttVT220,
- ttVT240,
- ttVT241,
- ttVT320,
- ttVT330,
- ttVT340,
- ttVT382,
- ttVT420,
- ttVT510,
- ttVT520,
- ttVT525
- );
- TDecConformanceLevel = (
- dclVT52,
- dclVT100, { VT100/VT101/VT102/VT105/VT125/VT131/VT180 }
- dclVT200, { VT220/VT240/VT241 }
- dclVT300, { VT320/VT340 }
- dclVT400, { VT420 }
- dclVT500 { VT510/VT520/VT525 }
- );
- TGCharacterSet = (
- gcsG0,
- gcsG1,
- gcsG2,
- gcsG3
- );
- TDecCharacterSet = (
- dcsUSASCII, { VT100 }
- dcsBritishNRCS, { VT100 }
- dcsFinnishNRCS, { VT200 }
- dcsSwedishNRCS, { VT200 }
- dcsGermanNRCS, { VT200 }
- dcsFrenchCanadianNRCS, { VT200 }
- dcsFrenchNRCS, { VT200 }
- dcsItalianNRCS, { VT200 }
- dcsSpanishNRCS, { VT200 }
- dcsDutchNRCS, { VT200 }
- dcsGreekNRCS, { VT500 }
- dcsTurkishNRCS, { VT500 }
- dcsPortugueseNRCS, { VT300 }
- dcsHebrewNRCS, { VT500 }
- dcsSwissNRCS, { VT200 }
- dcsNorwegianDanishNRCS, { VT200 }
- dcsDecSpecialGraphics, { VT100 }
- dcsDecSupplemental, { VT200 }
- dcsDecTechnical, { VT300 }
- dcsDecHebrew, { VT500 }
- dcsDecGreek, { VT500 }
- dcsDecTurkish, { VT500 }
- dcsDecCyrillic, { VT500 }
- dcsScsNRCS, { VT500 }
- dcsRussianNRCS, { VT500 }
- { 96-character sets }
- dcsISOLatin1Supplemental, { VT300 }
- dcsISOLatin2Supplemental, { VT500 }
- dcsISOGreekSupplemental, { VT500 }
- dcsISOHebrewSupplemental, { VT500 }
- dcsISOLatinCyrillic, { VT500 }
- dcsISOLatin5Supplemental { VT500 }
- );
- const
- CharacterSets96 = [dcsISOLatin1Supplemental..dcsISOLatin5Supplemental];
- type
- TVT52CharacterSet = (
- v52csASCII,
- v52csGraphics
- );
- const
- DefaultModeFlags: TTerminalModeFlags = [tmfAutoWrapMode, tmfSendReceiveMode, tmfUTF8Mode];
- MaxWidth = 65536;
- type
- TTransmitDataEvent = procedure(const buf; Bytes: SizeUInt) of object;
- TResizeEvent = procedure(NewWidth, NewHeight: Integer) of object;
- TTerminalSavedCursorFlag = (
- tscfOriginMode,
- tscfNextCharacterWrapsToNextLine
- );
- TTerminalSavedCursorFlags = set of TTerminalSavedCursorFlag;
- const
- DefaultSavedCursorFlags: TTerminalSavedCursorFlags = [];
- type
- { TTerminalSavedCursor }
- TTerminalSavedCursor = class
- private
- FCursorX: Integer;
- FCursorY: Integer;
- FCursorVisible: Boolean;
- FAttribute: TAttribute;
- FGLCharacterSet: TGCharacterSet;
- FGRCharacterSet: TGCharacterSet;
- FGCharacterSets: array [TGCharacterSet] of TDecCharacterSet;
- FFlags: TTerminalSavedCursorFlags;
- function GetCharacterSets(Index: TGCharacterSet): TDecCharacterSet;
- procedure SetCharacterSets(Index: TGCharacterSet; AValue: TDecCharacterSet);
- public
- constructor Create;
- procedure Reset;
- property CursorX: Integer read FCursorX write FCursorX;
- property CursorY: Integer read FCursorY write FCursorY;
- property CursorVisible: Boolean read FCursorVisible write FCursorVisible;
- property Attribute: TAttribute read FAttribute write FAttribute;
- property GLCharacterSet: TGCharacterSet read FGLCharacterSet write FGLCharacterSet;
- property GRCharacterSet: TGCharacterSet read FGRCharacterSet write FGRCharacterSet;
- property GCharacterSets[Index: TGCharacterSet]: TDecCharacterSet read GetCharacterSets write SetCharacterSets;
- property Flags: TTerminalSavedCursorFlags read FFlags write FFlags;
- end;
- { TTerminalTabStops }
- TTerminalTabStops = class
- private
- FTabStops: bitpacked array [0..MaxWidth - 1] of Boolean;
- function GetTabStop(Index: Integer): Boolean;
- procedure SetTabStop(Index: Integer; AValue: Boolean);
- public
- constructor Create;
- procedure Clear;
- procedure Reset;
- property TabStop[Index: Integer]: Boolean read GetTabStop write SetTabStop; default;
- end;
- { TTerminalController }
- TTerminalController = class
- private
- function GetCursorHomeX: Integer;
- function GetCursorHomeY: Integer;
- function GetCursorLimitX: Integer;
- function GetCursorLimitY: Integer;
- function GetCursorMinX: Integer;
- function GetCursorMinY: Integer;
- function GetCursorOriginX: Integer;
- function GetCursorOriginY: Integer;
- private
- FTerminalType: TTerminalType;
- FState: TTerminalStateMachineState;
- FUTF8_Build: LongWord;
- FLastGraphicCharacter: TExtendedGraphemeCluster;
- FNextCharacterWrapsToNextLine: Boolean;
- FSavedCursor: TTerminalSavedCursor;
- FAttribute: TAttribute;
- FModeFlags: TTerminalModeFlags;
- FDecConformanceLevel: TDecConformanceLevel;
- FDesignatingCharacterSet: TGCharacterSet;
- FGLCharacterSet: TGCharacterSet;
- FGRCharacterSet: TGCharacterSet;
- FGCharacterSets: array [TGCharacterSet] of TDecCharacterSet;
- FVT52CharacterSet: TVT52CharacterSet;
- FScrollingRegionTop: Integer;
- FScrollingRegionBottom: Integer;
- FScrollingRegionLeft: Integer;
- FScrollingRegionRight: Integer;
- {CSI control sequence}
- FControlSequenceParameter: string;
- FControlSequenceIntermediate: string;
- FControlSequenceFinalByte: Char;
- {OSC}
- FOperatingSystemCommand: string;
- {DCS}
- FDeviceControlString: string;
- FMouseTrackingMode: TTerminalMouseTrackingMode;
- FMouseProtocolEncoding: TTerminalMouseProtocolEncoding;
- FOldMouseX, FOldMouseY: Integer;
- FOldMouseButtons: TPointingDeviceButtonState;
- FTabStops: TTerminalTabStops;
- FModel: TTerminalModel;
- FOnTransmitData: TTransmitDataEvent;
- FOnResize: TResizeEvent;
- FLogger: TLogger;
- FVT100AnswerbackString: string;
- function ParseControlSequenceParams_Int(const CommandName: string; var i1: Integer): Boolean;
- function ParseControlSequenceParams_Int_Int(const CommandName: string; var i1, i2: Integer): Boolean;
- procedure SaveCursor;
- procedure RestoreCursor;
- procedure ClearControlSequence;
- procedure ExecuteControlSequence;
- procedure ExecuteOSC;
- procedure ExecuteDCS;
- procedure ExecuteDECRQSS(const ReqStr: string);
- procedure HandleSGRAttribute(SGRAttr: string);
- procedure ScrollUp(LinesCount: Integer = 1);
- procedure ScrollDown(LinesCount: Integer = 1);
- procedure ScrollLeft(CharCount: Integer);
- procedure ScrollRight(CharCount: Integer);
- procedure InsertLines(LinesCount: Integer);
- procedure DeleteLines(LinesCount: Integer);
- procedure DeleteCharacters(CharCount: Integer);
- procedure ErasePage;
- procedure ErasePageToBottom;
- procedure ErasePageToTop;
- procedure EraseLineToRight;
- procedure EraseLineToLeft;
- procedure EraseLine;
- procedure EraseCharacters(CharCount: Integer);
- procedure InsertBlankCharacters(CharCount: Integer);
- procedure WriteUTF32Char(const UTF32Char: LongWord);
- procedure WriteVT100CharFromCharset(Ch: Char; Charset: TDecCharacterSet);
- procedure WriteVT100Char(Ch: Char);
- procedure WriteVT52Char(Ch: Char);
- procedure WriteRepeatedCharacter(const EGC: TExtendedGraphemeCluster; Count: Integer);
- procedure HandleC1(Ch: TC1Char);
- procedure HandleENQ;
- procedure HandleCR;
- procedure HandleLF;
- procedure HandleBS;
- procedure HandleHT;
- procedure CursorForwardTabulation(TabStops: Integer);
- procedure CursorBackwardTabulation(TabStops: Integer);
- procedure EnterVT52Mode;
- procedure LeaveVT52Mode;
- procedure TransmitData(const buf; Bytes: SizeUInt);
- procedure TransmitStr(const S: string);
- procedure HardReset;
- procedure SoftReset;
- property CursorHomeX: Integer read GetCursorHomeX;
- property CursorHomeY: Integer read GetCursorHomeY;
- property CursorOriginX: Integer read GetCursorOriginX;
- property CursorOriginY: Integer read GetCursorOriginY;
- property CursorMinX: Integer read GetCursorMinX;
- property CursorMinY: Integer read GetCursorMinY;
- property CursorLimitX: Integer read GetCursorLimitX;
- property CursorLimitY: Integer read GetCursorLimitY;
- public
- constructor Create(AModel: TTerminalModel; ATerminalType: TTerminalType);
- destructor Destroy; override;
- function Resize(NewWidth, NewHeight: Integer): Boolean;
- procedure ReceiveData(const buf; Bytes: SizeUInt);
- procedure MaybeLocalEcho(const ks: rawbytestring);
- procedure HandleMouseEvent(const pdev: TPointingDeviceEvent);
- function EncodeReturnC1(Ch: TC1Char): string;
- property OnTransmitData: TTransmitDataEvent read FOnTransmitData write FOnTransmitData;
- property OnResize: TResizeEvent read FOnResize write FOnResize;
- property ModeFlags: TTerminalModeFlags read FModeFlags;
- property VT100AnswerbackString: string read FVT100AnswerbackString write FVT100AnswerbackString;
- property TerminalType: TTerminalType read FTerminalType;
- end;
- implementation
- uses
- {$IFDEF FPC_DOTTEDUNITS}
- System.SysUtils, System.Math;
- {$ELSE FPC_DOTTEDUNITS}
- SysUtils, Math;
- {$ENDIF FPC_DOTTEDUNITS}
- const
- MaxConformanceLevelForTerminal: array [TTerminalType] of TDecConformanceLevel = (
- dclVT52, { ttVT52 }
- dclVT100, { ttVT100 }
- dclVT100, { ttVT101 }
- dclVT100, { ttVT102 }
- dclVT100, { ttVT125 }
- dclVT100, { ttVT131 }
- dclVT100, { ttVT132 }
- dclVT200, { ttVT220 }
- dclVT200, { ttVT240 }
- dclVT200, { ttVT241 }
- dclVT300, { ttVT320 }
- dclVT300, { ttVT330 }
- dclVT300, { ttVT340 }
- dclVT300, { ttVT382 }
- dclVT400, { ttVT420 }
- dclVT500, { ttVT510 }
- dclVT500, { ttVT520 }
- dclVT500 { ttVT525 }
- );
- DecSpecialGraphicsCharacterSet: array [#$5F..#$7E] of UCS4Char = (
- $0020,
- $25C6, $2592, $2409, $240C, $240D, $240A, $00B0, $00B1, $2424, $240B, $2518, $2510, $250C, $2514, $253C, $23BA,
- $23BB, $2500, $23BC, $23BD, $251C, $2524, $2534, $252C, $2502, $2264, $2265, $03A0, $2260, $00A3, $00B7
- );
- DecTechnicalCharacterSet: array [#$21..#$7E] of UCS4Char = (
- $23B7, $250C, $2500, $2320, $2321, $2502, $23A1, $23A3, $23A4, $23A6, $23A7, $23A9, $23AB, $23AD, $23A8,
- $23AC, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $2264, $2260, $2265, $222B,
- $2234, $221D, $221E, $00F7, $0394, $2207, $03A6, $0393, $223C, $2243, $0398, $00D7, $039B, $21D4, $21D2, $2261,
- $03A0, $03A8, $FFFD, $03A3, $FFFD, $FFFD, $221A, $03A9, $039E, $03A5, $2282, $2283, $2229, $222A, $2227, $2228,
- $00AC, $03B1, $03B2, $03C7, $03B4, $03B5, $03C6, $03B3, $03B7, $03B9, $03B8, $03BA, $03BB, $FFFD, $03BD, $2202,
- $03C0, $03C8, $03C1, $03C3, $03C4, $FFFD, $0192, $03C9, $03BE, $03C5, $03B6, $2190, $2191, $2192, $2193
- );
- DecCyrillicCharacterSet: array [#$40..#$7E] of UCS4Char = (
- $044E, $0430, $0431, $0446, $0434, $0435, $0444, $0433, $0445, $0438, $0439, $043A, $043B, $043C, $043D, $043E,
- $043F, $044F, $0440, $0441, $0442, $0443, $0436, $0432, $044C, $044B, $0437, $0448, $044D, $0449, $0447, $044A,
- $042E, $0410, $0411, $0426, $0414, $0415, $0424, $0413, $0425, $0418, $0419, $041A, $041B, $041C, $041D, $041E,
- $041F, $042F, $0420, $0421, $0422, $0423, $0416, $0412, $042C, $042B, $0417, $0428, $042D, $0429, $0427
- );
- VT52GraphicsCharacterSet: array [#$5E..#$7E] of UCS4Char = (
- $0020, $0020,
- $0020, $2588, $215F, $00B3, $2075, $2077, $00B0, $00B1, $2192, $2026, $00F7, $2193, $2594,$1FB76,$1FB77,$1FB78,
- $1FB79,$1FB7A,$1FB7B, $2581, $2080, $2081, $2082, $2083, $2084, $2085, $2086, $2087, $2088, $2089, $00B6
- );
- function OnlyDigits(const S: string): Boolean;
- var
- Ch: Char;
- begin
- for Ch in S do
- if (Ch < '0') or (Ch > '9') then
- exit(False);
- Result := True;
- end;
- function ExtractStringParameter(var S: string): string;
- var
- I: SizeInt;
- begin
- I := Pos(';', S);
- if I = 0 then
- begin
- Result := S;
- S := '';
- end
- else
- begin
- Result := Copy(S, 1, I - 1);
- Delete(S, 1, I);
- end;
- end;
- function ExtractSGRParameter(var S: string): string;
- var
- P1, P2: LongInt;
- P2S, P3S, P4S, P5S: string;
- begin
- Result := ExtractStringParameter(S);
- if (Result <> '') and OnlyDigits(Result) then
- begin
- P1 := StrToInt(Result);
- if (P1 = 38) or (P1 = 48) then
- begin
- P2S := ExtractStringParameter(S);
- Result := Result + ':' + P2S;
- if (P2S <> '') and OnlyDigits(P2S) then
- begin
- P2 := StrToInt(P2S);
- case P2 of
- 5:
- begin
- P3S := ExtractStringParameter(S);
- if OnlyDigits(P3S) then
- Result := Result + ':' + P3S;
- end;
- 2:
- begin
- P3S := ExtractStringParameter(S);
- if OnlyDigits(P3S) then
- begin
- P4S := ExtractStringParameter(S);
- if OnlyDigits(P4S) then
- begin
- P5S := ExtractStringParameter(S);
- if OnlyDigits(P5S) then
- Result := Result + ':' + P3S + ':' + P4S + ':' + P5S;
- end
- else
- Result := Result + ':' + P3S + ':' + P4S;
- end
- else
- Result := Result + ':' + P3S;
- end;
- end;
- end;
- end;
- end;
- end;
- function ExtractIntParameter(var S: string; Default: Integer): Integer;
- var
- ParamS: string;
- begin
- ParamS := ExtractStringParameter(S);
- if ParamS = '' then
- Result := Default
- else
- Result := StrToInt(ParamS);
- end;
- { TTerminalSavedCursor }
- function TTerminalSavedCursor.GetCharacterSets(Index: TGCharacterSet): TDecCharacterSet;
- begin
- Result := FGCharacterSets[Index];
- end;
- procedure TTerminalSavedCursor.SetCharacterSets(Index: TGCharacterSet; AValue: TDecCharacterSet);
- begin
- FGCharacterSets[Index] := AValue;
- end;
- constructor TTerminalSavedCursor.Create;
- begin
- Reset;
- end;
- procedure TTerminalSavedCursor.Reset;
- begin
- FCursorX := 0;
- FCursorY := 0;
- FCursorVisible := True;
- FAttribute := DefaultAttribute;
- FGLCharacterSet := gcsG0;
- FGRCharacterSet := gcsG1;
- FGCharacterSets[gcsG0] := dcsUSASCII;
- FGCharacterSets[gcsG1] := dcsUSASCII;
- FGCharacterSets[gcsG2] := dcsUSASCII;
- FGCharacterSets[gcsG3] := dcsUSASCII;
- FFlags := DefaultSavedCursorFlags;
- end;
- { TTerminalTabStops }
- function TTerminalTabStops.GetTabStop(Index: Integer): Boolean;
- begin
- if (Index >= Low(FTabStops)) and (Index <= High(FTabStops)) then
- Result := FTabStops[Index]
- else
- Result := False;
- end;
- procedure TTerminalTabStops.SetTabStop(Index: Integer; AValue: Boolean);
- begin
- if (Index >= Low(FTabStops)) and (Index <= High(FTabStops)) then
- FTabStops[Index] := AValue;
- end;
- constructor TTerminalTabStops.Create;
- begin
- Reset;
- end;
- procedure TTerminalTabStops.Clear;
- begin
- FillChar(FTabStops, SizeOf(FTabStops), 0);
- end;
- procedure TTerminalTabStops.Reset;
- var
- I: Integer;
- begin
- Clear;
- for I := 0 to High(FTabStops) div 8 do
- TabStop[I * 8] := True;
- end;
- { TTerminalController }
- function TTerminalController.GetCursorHomeX: Integer;
- begin
- Result := 0;
- end;
- function TTerminalController.GetCursorHomeY: Integer;
- begin
- if tmfOriginMode in FModeFlags then
- Result := FScrollingRegionTop
- else
- Result := 0;
- end;
- function TTerminalController.GetCursorLimitX: Integer;
- begin
- Result := FModel.Width - 1;
- end;
- function TTerminalController.GetCursorLimitY: Integer;
- begin
- if tmfOriginMode in FModeFlags then
- Result := FScrollingRegionBottom
- else
- Result := FModel.Height - 1;
- end;
- function TTerminalController.GetCursorMinX: Integer;
- begin
- Result := 0;
- end;
- function TTerminalController.GetCursorMinY: Integer;
- begin
- Result := CursorHomeY;
- end;
- function TTerminalController.GetCursorOriginX: Integer;
- begin
- Result := 0;
- end;
- function TTerminalController.GetCursorOriginY: Integer;
- begin
- Result := CursorHomeY;
- end;
- function TTerminalController.ParseControlSequenceParams_Int(const CommandName: string; var i1: Integer): Boolean;
- var
- S: string;
- begin
- Result := False;
- if FControlSequenceIntermediate <> '' then
- begin
- FLogger.LogMessage(vlWarning, 'Unhandled ' + CommandName + ' intermediate bytes: ' + FControlSequenceIntermediate);
- exit;
- end;
- S := FControlSequenceParameter;
- try
- i1 := ExtractIntParameter(S, i1);
- except
- on e: EConvertError do
- begin
- FLogger.LogMessage(vlWarning, 'Invalid ' + CommandName + ' integer parameter: ' + FControlSequenceParameter);
- exit;
- end;
- end;
- if S <> '' then
- begin
- FLogger.LogMessage(vlWarning, 'Too many ' + CommandName + ' parameters: ' + FControlSequenceParameter);
- exit;
- end;
- Result := True;
- end;
- function TTerminalController.ParseControlSequenceParams_Int_Int(const CommandName: string; var i1, i2: Integer): Boolean;
- var
- S: string;
- begin
- Result := False;
- if FControlSequenceIntermediate <> '' then
- begin
- FLogger.LogMessage(vlWarning, 'Unhandled ' + CommandName + ' intermediate bytes: ' + FControlSequenceIntermediate);
- exit;
- end;
- S := FControlSequenceParameter;
- try
- i1 := ExtractIntParameter(S, i1);
- i2 := ExtractIntParameter(S, i2);
- except
- on e: EConvertError do
- begin
- FLogger.LogMessage(vlWarning, 'Invalid ' + CommandName + ' integer parameter: ' + FControlSequenceParameter);
- exit;
- end;
- end;
- if S <> '' then
- begin
- FLogger.LogMessage(vlWarning, 'Too many ' + CommandName + ' parameters: ' + FControlSequenceParameter);
- exit;
- end;
- Result := True;
- end;
- procedure TTerminalController.SaveCursor;
- var
- Flags: TTerminalSavedCursorFlags;
- begin
- { todo: shape, other attributes? }
- FSavedCursor.CursorX := FModel.CursorX;
- FSavedCursor.CursorY := FModel.CursorY;
- FSavedCursor.CursorVisible := FModel.CursorVisible;
- FSavedCursor.Attribute := FAttribute;
- FSavedCursor.GLCharacterSet := FGLCharacterSet;
- FSavedCursor.GRCharacterSet := FGRCharacterSet;
- FSavedCursor.GCharacterSets[gcsG0] := FGCharacterSets[gcsG0];
- FSavedCursor.GCharacterSets[gcsG1] := FGCharacterSets[gcsG1];
- FSavedCursor.GCharacterSets[gcsG2] := FGCharacterSets[gcsG2];
- FSavedCursor.GCharacterSets[gcsG3] := FGCharacterSets[gcsG3];
- Flags := [];
- if tmfOriginMode in ModeFlags then
- Include(Flags, tscfOriginMode);
- if FNextCharacterWrapsToNextLine then
- Include(Flags, tscfNextCharacterWrapsToNextLine);
- FSavedCursor.Flags := Flags;
- end;
- procedure TTerminalController.RestoreCursor;
- begin
- { todo: shape, other attributes? }
- FModel.SetCursorPos(EnsureRange(FSavedCursor.CursorX, CursorMinX, CursorLimitX), EnsureRange(FSavedCursor.FCursorY, CursorMinY, CursorLimitY));
- FNextCharacterWrapsToNextLine := tscfNextCharacterWrapsToNextLine in FSavedCursor.Flags;
- if FSavedCursor.CursorVisible then
- FModel.ShowCursor
- else
- FModel.HideCursor;
- FAttribute := FSavedCursor.Attribute;
- FGLCharacterSet := FSavedCursor.GLCharacterSet;
- FGRCharacterSet := FSavedCursor.GRCharacterSet;
- FGCharacterSets[gcsG0] := FSavedCursor.GCharacterSets[gcsG0];
- FGCharacterSets[gcsG1] := FSavedCursor.GCharacterSets[gcsG1];
- FGCharacterSets[gcsG2] := FSavedCursor.GCharacterSets[gcsG2];
- FGCharacterSets[gcsG3] := FSavedCursor.GCharacterSets[gcsG3];
- if tscfOriginMode in FSavedCursor.Flags then
- Include(FModeFlags, tmfOriginMode)
- else
- Exclude(FModeFlags, tmfOriginMode);
- end;
- procedure TTerminalController.ClearControlSequence;
- begin
- FControlSequenceParameter := '';
- FControlSequenceIntermediate := '';
- FControlSequenceFinalByte := #0;
- end;
- procedure TTerminalController.ExecuteControlSequence;
- procedure HandleSGR;
- var
- S, PS: string;
- I: SizeInt;
- begin
- if FControlSequenceIntermediate <> '' then
- FLogger.LogMessage(vlWarning, 'Unhandled SGR intermediate bytes: ' + FControlSequenceIntermediate);
- S := FControlSequenceParameter;
- if S = '' then
- S := '0';
- while S <> '' do
- begin
- PS := ExtractSGRParameter(S);
- HandleSGRAttribute(PS);
- end;
- end;
- var
- n, m: Integer;
- begin
- case FControlSequenceFinalByte of
- '@':
- begin
- if FControlSequenceIntermediate = ' ' then
- begin
- { SL - SCROLL LEFT }
- n := 1;
- FControlSequenceIntermediate := '';
- if ParseControlSequenceParams_Int('SL', n) then
- ScrollLeft(n);
- end
- else
- begin
- { ICH - INSERT CHARACTER }
- n := 1;
- if ParseControlSequenceParams_Int('ICH', n) then
- InsertBlankCharacters(n);
- end;
- end;
- { CUU - CURSOR UP }
- 'A':
- begin
- if FControlSequenceIntermediate = ' ' then
- begin
- { SR - SCROLL RIGHT }
- n := 1;
- FControlSequenceIntermediate := '';
- if ParseControlSequenceParams_Int('SR', n) then
- ScrollRight(n);
- end
- else
- begin
- n := 1;
- if ParseControlSequenceParams_Int('CUU', n) then
- begin
- FModel.SetCursorPos(FModel.CursorX, Max(FModel.CursorY - Max(n, 1), CursorMinY));
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- end;
- { CUD - CURSOR DOWN }
- 'B':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('CUD', n) then
- begin
- FModel.SetCursorPos(FModel.CursorX, Min(FModel.CursorY + Max(n, 1), CursorLimitY));
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { CUF - CURSOR RIGHT }
- 'C':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('CUF', n) then
- begin
- FModel.SetCursorPos(Min(FModel.CursorX + Max(n, 1), CursorLimitX), FModel.CursorY);
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { CUB - CURSOR LEFT }
- 'D':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('CUB', n) then
- begin
- FModel.SetCursorPos(Max(FModel.CursorX - Max(n, 1), CursorMinX), FModel.CursorY);
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { CNL - CURSOR NEXT LINE }
- 'E':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('CNL', n) then
- begin
- FModel.SetCursorPos(0, Min(FModel.CursorY + Max(n, 1), CursorLimitY));
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { CPL - CURSOR PRECEDING LINE }
- 'F':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('CPL', n) then
- begin
- FModel.SetCursorPos(0, Max(FModel.CursorY - Max(n, 1), CursorMinY));
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { CHA - CURSOR CHARACTER ABSOLUTE }
- 'G':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('CHA', n) then
- begin
- FModel.SetCursorPos(EnsureRange(n - 1, CursorMinX, CursorLimitX), FModel.CursorY);
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { CUP - CURSOR POSITION }
- 'H':
- begin
- n := 1;
- m := 1;
- if ParseControlSequenceParams_Int_Int('CUP', n, m) then
- begin
- FModel.SetCursorPos(EnsureRange(CursorOriginX + Max(m, 1) - 1, CursorMinX, CursorLimitX), EnsureRange(CursorOriginY + Max(n, 1) - 1, CursorMinY, CursorLimitY));
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { CHT - CURSOR FORWARD TABULATION }
- 'I':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('CHT', n) then
- CursorForwardTabulation(n);
- end;
- { ED - ERASE IN PAGE }
- 'J':
- begin
- n := 0;
- if ParseControlSequenceParams_Int('ED', n) then
- case n of
- 0:
- ErasePageToBottom;
- 1:
- ErasePageToTop;
- 2:
- ErasePage;
- else
- FLogger.LogMessage(vlWarning, 'Unsupported ED parameter: ' + FControlSequenceParameter);
- end;
- end;
- { EL - ERASE IN LINE }
- 'K':
- begin
- n := 0;
- if ParseControlSequenceParams_Int('EL', n) then
- case n of
- 0:
- EraseLineToRight;
- 1:
- EraseLineToLeft;
- 2:
- EraseLine;
- else
- FLogger.LogMessage(vlWarning, 'Unsupported EL parameter: ' + FControlSequenceParameter);
- end;
- end;
- { IL - INSERT LINE }
- 'L':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('IL', n) then
- InsertLines(n);
- end;
- { DL - DELETE LINE }
- 'M':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('DL', n) then
- DeleteLines(n);
- end;
- { DCH - DELETE CHARACTER }
- 'P':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('DCH', n) then
- DeleteCharacters(n);
- end;
- { SU - SCROLL UP }
- 'S':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('SU', n) then
- ScrollUp(n);
- end;
- { SD - SCROLL DOWN }
- 'T':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('SD', n) then
- { unlike "CSI 0 S" and "CSI 0 ^", which scroll by one, "CSI 0 T" doesn't do anything in xterm }
- if n <> 0 then
- ScrollDown(n);
- end;
- { ECH - ERASE CHARACTER }
- 'X':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('ECH', n) then
- EraseCharacters(n);
- end;
- { CBT - CURSOR BACKWARD TABULATION }
- 'Z':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('CBT', n) then
- CursorBackwardTabulation(n);
- end;
- { SD - SCROLL DOWN - ECMA-48, publication error in the original ECMA-48 5th edition (1991), corrected in 2003 }
- '^':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('SD', n) then
- ScrollDown(n);
- end;
- { HPA - CHARACTER POSITION ABSOLUTE }
- '`':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('HPA', n) then
- begin
- FModel.SetCursorPos(EnsureRange(CursorOriginX + Max(n, 1) - 1, CursorMinX, CursorLimitX), FModel.CursorY);
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { HPR - CHARACTER POSITION FORWARD }
- 'a':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('HPR', n) then
- begin
- FModel.SetCursorPos(Min(FModel.CursorX + Max(n, 1), CursorLimitY), FModel.CursorY);
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { REP - REPEAT }
- 'b':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('REP', n) then
- begin
- if FLastGraphicCharacter <> '' then
- WriteRepeatedCharacter(FLastGraphicCharacter, Max(n, 1));
- FLastGraphicCharacter := '';
- end;
- end;
- { DA - DEVICE ATTRIBUTES }
- 'c':
- begin
- if (Length(FControlSequenceParameter) >= 1) and (FControlSequenceParameter[1] = '>') then
- begin
- { Secondary DA }
- Delete(FControlSequenceParameter, 1, 1);
- n := 0;
- if ParseControlSequenceParams_Int('Secondary DA', n) then
- TransmitStr(EncodeReturnC1(C1_CSI) + '>41;371;0c');
- end
- else
- if (Length(FControlSequenceParameter) >= 1) and (FControlSequenceParameter[1] = '=') then
- begin
- { Tertiary DA }
- Delete(FControlSequenceParameter, 1, 1);
- n := 0;
- if ParseControlSequenceParams_Int('Tertiary DA', n) then
- TransmitStr(EncodeReturnC1(C1_DCS) + '!|00000000' + EncodeReturnC1(C1_ST));
- end
- else
- begin
- { Primary DA }
- n := 0;
- if ParseControlSequenceParams_Int('DA', n) then
- begin
- case TerminalType of
- ttVT100:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?1;2c');
- ttVT101:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?1;0c');
- ttVT102:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?6c');
- ttVT125:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?12;2;0;372c');
- ttVT131:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?7c');
- ttVT132:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?4;2c');
- ttVT220:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?62;1;2;6;9;15;16;22;28c');
- ttVT240,
- ttVT241:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?62;1;2;4;6;9;15;16;22;28c');
- ttVT320:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?63;1;2;6;9;15;16;22;28c');
- ttVT330,
- ttVT340,
- ttVT382:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?63;1;2;4;6;9;15;16;22;28c');
- ttVT420:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?64;1;2;6;9;15;16;17;18;21;22;28c');
- ttVT510,
- ttVT520,
- ttVT525:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?65;1;2;6;9;15;16;17;18;21;22;28c');
- end;
- end;
- end;
- end;
- { VPA - LINE POSITION ABSOLUTE }
- 'd':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('VPA', n) then
- begin
- FModel.SetCursorPos(FModel.CursorX, EnsureRange(CursorOriginY + Max(n, 1) - 1, CursorMinY, CursorLimitY));
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { VPR - LINE POSITION FORWARD }
- 'e':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('VPR', n) then
- begin
- FModel.SetCursorPos(FModel.CursorX, Min(FModel.CursorY + Max(n, 1), CursorLimitY));
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { HVP - CHARACTER AND LINE POSITION }
- 'f':
- begin
- n := 1;
- m := 1;
- if ParseControlSequenceParams_Int_Int('HVP', n, m) then
- begin
- FModel.SetCursorPos(EnsureRange(CursorHomeX + Max(m, 1) - 1, CursorMinX, CursorLimitX), EnsureRange(CursorHomeY + Max(n, 1) - 1, CursorMinY, CursorLimitY));
- FNextCharacterWrapsToNextLine := False;
- end;
- end;
- { TBC - TABULATION CLEAR }
- 'g':
- begin
- n := 0;
- if ParseControlSequenceParams_Int('TBC', n) then
- case n of
- 0:
- FTabStops[FModel.CursorX] := False;
- 3:
- FTabStops.Clear;
- else
- FLogger.LogMessage(vlWarning, 'Unhandled TBC: ' + IntToStr(n));
- end;
- end;
- { SM - SET MODE }
- 'h':
- begin
- if (Length(FControlSequenceParameter) > 1) and (FControlSequenceParameter[1] = '?') then
- begin
- { DEC Private Mode Set (DECSET) }
- Delete(FControlSequenceParameter, 1, 1);
- while FControlSequenceParameter <> '' do
- begin
- n := ExtractIntParameter(FControlSequenceParameter, -1);
- case n of
- 1:
- Include(FModeFlags, tmfCursorKeysSendApplicationSequences);
- 3:
- if tmfAllow80To132ModeSwitching in FModeFlags then
- begin
- FScrollingRegionTop := 0;
- FScrollingRegionBottom := FModel.Height - 1;
- FScrollingRegionLeft := 0;
- FScrollingRegionRight := FModel.Width - 1;
- FModel.SetCursorPos(CursorHomeX, CursorHomeY);
- ErasePage;
- Resize(132, FModel.Height);
- end;
- 5:
- begin
- Include(FModeFlags, tmfReverseVideo);
- FModel.ReverseVideo := True;
- end;
- 6:
- begin
- Include(FModeFlags, tmfOriginMode);
- FModel.SetCursorPos(CursorHomeX, CursorHomeY);
- end;
- 7:
- Include(FModeFlags, tmfAutoWrapMode);
- 9:
- FMouseTrackingMode := tmtmX10;
- 12:
- FModel.StartBlinkingCursor;
- 25:
- FModel.ShowCursor;
- 40:
- Include(FModeFlags, tmfAllow80To132ModeSwitching);
- 1000:
- FMouseTrackingMode := tmtmNormal;
- 1002:
- FMouseTrackingMode := tmtmButtonEvent;
- 1003:
- FMouseTrackingMode := tmtmAnyEvent;
- 1005:
- FMouseProtocolEncoding := tmpeUTF8;
- 1006:
- FMouseProtocolEncoding := tmpeSGR;
- 1049:
- begin
- SaveCursor;
- FModel.CurrentVisibleScreenBuffer := sbAlternate;
- end;
- 2004:
- Include(FModeFlags, tmfBracketedPasteMode);
- else
- FLogger.LogMessage(vlWarning, 'Unhandled DECSET: ' + IntToStr(n));
- end;
- end;
- end
- else
- begin
- while FControlSequenceParameter <> '' do
- begin
- n := ExtractIntParameter(FControlSequenceParameter, -1);
- case n of
- 2:
- Include(FModeFlags, tmfKeyboardActionMode);
- 4:
- Include(FModeFlags, tmfInsertMode);
- 12:
- Include(FModeFlags, tmfSendReceiveMode);
- 20:
- Include(FModeFlags, tmfAutoNewLine);
- else
- FLogger.LogMessage(vlWarning, 'Unhandled SET MODE: ' + IntToStr(n));
- end;
- end;
- end;
- end;
- { VPB - LINE POSITION BACKWARD }
- {'k':
- begin
- n := 1;
- if ParseControlSequenceParams_Int('VPB', n) then
- FModel.SetCursorPos(FModel.CursorX, Max(FModel.CursorY - Max(n, 1), 0));
- end;}
- { RM - RESET MODE }
- 'l':
- begin
- if (Length(FControlSequenceParameter) > 1) and (FControlSequenceParameter[1] = '?') then
- begin
- { DEC Private Mode Reset (DECRST) }
- Delete(FControlSequenceParameter, 1, 1);
- while FControlSequenceParameter <> '' do
- begin
- n := ExtractIntParameter(FControlSequenceParameter, -1);
- case n of
- 1:
- Exclude(FModeFlags, tmfCursorKeysSendApplicationSequences);
- 2:
- EnterVT52Mode;
- 3:
- if tmfAllow80To132ModeSwitching in FModeFlags then
- begin
- FScrollingRegionTop := 0;
- FScrollingRegionBottom := FModel.Height - 1;
- FScrollingRegionLeft := 0;
- FScrollingRegionRight := FModel.Width - 1;
- FModel.SetCursorPos(CursorHomeX, CursorHomeY);
- ErasePage;
- Resize(80, FModel.Height);
- end;
- 5:
- begin
- Exclude(FModeFlags, tmfReverseVideo);
- FModel.ReverseVideo := False;
- end;
- 6:
- begin
- Exclude(FModeFlags, tmfOriginMode);
- FModel.SetCursorPos(CursorHomeX, CursorHomeY);
- end;
- 7:
- Exclude(FModeFlags, tmfAutoWrapMode);
- 9:
- FMouseTrackingMode := tmtmNone;
- 12:
- FModel.StopBlinkingCursor;
- 25:
- FModel.HideCursor;
- 40:
- Exclude(FModeFlags, tmfAllow80To132ModeSwitching);
- 1000:
- FMouseTrackingMode := tmtmNone;
- 1002:
- FMouseTrackingMode := tmtmNone;
- 1003:
- FMouseTrackingMode := tmtmNone;
- 1005:
- FMouseProtocolEncoding := tmpeX10;
- 1006:
- FMouseProtocolEncoding := tmpeX10;
- 1049:
- begin
- FModel.CurrentVisibleScreenBuffer := sbNormal;
- RestoreCursor;
- end;
- 2004:
- Exclude(FModeFlags, tmfBracketedPasteMode);
- else
- FLogger.LogMessage(vlWarning, 'Unhandled DECRST: ' + IntToStr(n));
- end;
- end;
- end
- else
- begin
- while FControlSequenceParameter <> '' do
- begin
- n := ExtractIntParameter(FControlSequenceParameter, -1);
- case n of
- 2:
- Exclude(FModeFlags, tmfKeyboardActionMode);
- 4:
- Exclude(FModeFlags, tmfInsertMode);
- 12:
- Exclude(FModeFlags, tmfSendReceiveMode);
- 20:
- Exclude(FModeFlags, tmfAutoNewLine);
- else
- FLogger.LogMessage(vlWarning, 'Unhandled RESET MODE: ' + IntToStr(n));
- end;
- end;
- end;
- end;
- { SGR - SELECT GRAPHIC RENDITION }
- 'm':
- HandleSGR;
- { DSR - DEVICE STATUS REPORT }
- 'n':
- begin
- if (Length(FControlSequenceParameter) > 1) and (FControlSequenceParameter[1] = '?') then
- begin
- { DSR, DEC format }
- Delete(FControlSequenceParameter, 1, 1);
- n := -1;
- if ParseControlSequenceParams_Int('DSR_DEC', n) then
- case n of
- 6:
- if FDecConformanceLevel >= dclVT400 then
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(FModel.CursorY - CursorOriginY + 1) + ';' + IntToStr(FModel.CursorX - CursorOriginX + 1) + ';1R')
- else
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(FModel.CursorY - CursorOriginY + 1) + ';' + IntToStr(FModel.CursorX - CursorOriginX + 1) + 'R');
- { Report Printer status }
- 15:
- if FDecConformanceLevel >= dclVT200 then
- TransmitStr(EncodeReturnC1(C1_CSI) + '?13n'); { No printer }
- { Report UDK (User Defined Keys) status }
- 25:
- if FDecConformanceLevel >= dclVT200 then
- TransmitStr(EncodeReturnC1(C1_CSI) + '?20n'); { UDKs unlocked }
- { Report Keyboard status }
- 26:
- if FDecConformanceLevel >= dclVT400 then
- TransmitStr(EncodeReturnC1(C1_CSI) + '?27;1;0;0n')
- else if FDecConformanceLevel >= dclVT300 then
- TransmitStr(EncodeReturnC1(C1_CSI) + '?27;1;0n')
- else if FDecConformanceLevel >= dclVT200 then
- TransmitStr(EncodeReturnC1(C1_CSI) + '?27;1n');
- { Report Locator status }
- 53, 55:
- if FDecConformanceLevel >= dclVT300 then
- TransmitStr(EncodeReturnC1(C1_CSI) + '?53n'); { No locator }
- { Report Locator type }
- 56:
- if FDecConformanceLevel >= dclVT300 then
- TransmitStr(EncodeReturnC1(C1_CSI) + '?57;0n'); { Cannot identify }
- else
- FLogger.LogMessage(vlWarning, 'Unhandled DEC DEVICE STATUS REPORT: ' + IntToStr(n));
- end;
- end
- else
- begin
- { DSR, ANSI format }
- n := -1;
- if ParseControlSequenceParams_Int('DSR_ANSI', n) then
- case n of
- 5:
- TransmitStr(EncodeReturnC1(C1_CSI) + '0n');
- 6:
- TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(FModel.CursorY - CursorOriginY + 1) + ';' + IntToStr(FModel.CursorX - CursorOriginX + 1) + 'R');
- else
- FLogger.LogMessage(vlWarning, 'Unhandled ANSI DEVICE STATUS REPORT: ' + IntToStr(n));
- end;
- end;
- end;
- 'p':
- begin
- if FControlSequenceIntermediate = '"' then
- begin
- { DECSCL - Select Conformance Level (VT220+) }
- if TerminalType >= ttVT220 then
- begin
- FControlSequenceIntermediate := '';
- n := 0; { todo:??? }
- m := 0; { todo:??? }
- if ParseControlSequenceParams_Int_Int('DECSCL', n, m) then
- begin
- case n of
- 61:
- begin
- FDecConformanceLevel := dclVT100;
- m := 1;
- end;
- 62:
- FDecConformanceLevel := dclVT200;
- 63:
- FDecConformanceLevel := dclVT300;
- 64:
- FDecConformanceLevel := dclVT400;
- 65:
- FDecConformanceLevel := dclVT500;
- end;
- if FDecConformanceLevel > MaxConformanceLevelForTerminal[TerminalType] then
- FDecConformanceLevel := MaxConformanceLevelForTerminal[TerminalType];
- case m of
- 0, 2:
- Include(FModeFlags, tmfSend8BitC1Controls);
- 1:
- Exclude(FModeFlags, tmfSend8BitC1Controls);
- end;
- { todo: soft or hard reset? }
- end
- else
- FLogger.LogMessage(vlWarning, 'Unhandled CSI control sequence: ' + FControlSequenceParameter + '"' + FControlSequenceFinalByte);
- end;
- end
- else if FControlSequenceIntermediate = '$' then
- begin
- { DECRQM - Request ANSI/DEC private mode (VT300+) }
- if FDecConformanceLevel >= dclVT300 then
- begin
- FControlSequenceIntermediate := '';
- if (Length(FControlSequenceParameter) > 1) and (FControlSequenceParameter[1] = '?') then
- begin
- { Request DEC private mode }
- Delete(FControlSequenceParameter, 1, 1);
- n := 65535;
- if ParseControlSequenceParams_Int('DECRQM', n) then
- case n of
- 1:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfCursorKeysSendApplicationSequences in FModeFlags, 1, 2)) + '$y');
- 2:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';1$y');
- 3:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(FModel.Width >= 132, 1, 2)) + '$y');
- 5:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfReverseVideo in FModeFlags, 1, 2)) + '$y');
- 6:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfOriginMode in FModeFlags, 1, 2)) + '$y');
- 7:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfAutoWrapMode in FModeFlags, 1, 2)) + '$y');
- 25:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(FModel.CursorVisible, 1, 2)) + '$y');
- 40:
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfAllow80To132ModeSwitching in FModeFlags, 1, 2)) + '$y');
- { permanently reset }
- 8: { DECARM }
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';4$y');
- { permanently set }
- 14: { DECTEM }
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';3$y');
- else
- TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';0$y');
- end;
- end
- else
- begin
- { Request ANSI mode }
- n := 65535;
- if ParseControlSequenceParams_Int('DECRQM', n) then
- case n of
- 2:
- TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';' + IntToStr(IfThen(tmfKeyboardActionMode in FModeFlags, 1, 2)) + '$y');
- 3:
- TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';2$y');
- 4:
- TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';' + IntToStr(IfThen(tmfInsertMode in FModeFlags, 1, 2)) + '$y');
- 12:
- TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';' + IntToStr(IfThen(tmfSendReceiveMode in FModeFlags, 1, 2)) + '$y');
- 20:
- TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';' + IntToStr(IfThen(tmfAutoNewLine in FModeFlags, 1, 2)) + '$y');
- { permanently reset }
- 1, { GATM }
- 5, { KAM }
- 7, { SRTM }
- 10, { VEM }
- 11, { HEM }
- 13, { PUM }
- 14, { SRM }
- 15, { FEAM }
- 16, { TTM }
- 17, { SATM }
- 18, { TSM }
- 19: { EBM }
- TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';4$y');
- else
- TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';0$y');
- end;
- end;
- end;
- end
- else if FControlSequenceIntermediate = '!' then
- begin
- { DECSTR - Soft Terminal Reset (VT220+) }
- if FDecConformanceLevel >= dclVT200 then
- begin
- SoftReset;
- end;
- end
- else
- FLogger.LogMessage(vlWarning, 'Unhandled CSI control sequence: ' + FControlSequenceParameter + FControlSequenceIntermediate + FControlSequenceFinalByte);
- end;
- { DECSTBM - Set Top and Bottom Margins }
- 'r':
- begin
- n := 1;
- m := FModel.Height;
- if ParseControlSequenceParams_Int_Int('DECSTBM', n, m) then
- begin
- if n = 0 then
- n := 1;
- if m = 0 then
- m := FModel.Height;
- if n > FModel.Height then
- n := FModel.Height;
- if m > FModel.Height then
- m := FModel.Height;
- if n < m then
- begin
- FScrollingRegionTop := n - 1;
- FScrollingRegionBottom := m - 1;
- FModel.SetCursorPos(CursorHomeX, CursorHomeY);
- end;
- end;
- end;
- { DECREQTPARM - Request Terminal Parameters }
- 'x':
- begin
- n := 0;
- if ParseControlSequenceParams_Int('DECREQTPARM', n) then
- begin
- case n of
- 0, 1:
- begin
- TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n + 2) + ';1;1;120;120;1;0x');
- end;
- end;
- end;
- end;
- else
- FLogger.LogMessage(vlWarning, 'Unhandled CSI control sequence: ' + FControlSequenceParameter + FControlSequenceIntermediate + FControlSequenceFinalByte);
- end;
- end;
- procedure TTerminalController.ExecuteOSC;
- begin
- {...}
- FLogger.LogMessage(vlWarning, 'Unhandled OSC control sequence: ' + FOperatingSystemCommand);
- end;
- procedure TTerminalController.ExecuteDCS;
- begin
- if (Length(FDeviceControlString) >= 2) and (FDeviceControlString[1] = '$') and (FDeviceControlString[2] = 'q') then
- ExecuteDECRQSS(Copy(FDeviceControlString, 3, Length(FDeviceControlString) - 2))
- else
- FLogger.LogMessage(vlWarning, 'Unhandled DCS control sequence: ' + FDeviceControlString);
- end;
- procedure TTerminalController.ExecuteDECRQSS(const ReqStr: string);
- function ConformanceLevel2ID: Integer;
- begin
- case FDecConformanceLevel of
- dclVT200:
- Result := 62;
- dclVT300:
- Result := 63;
- dclVT400:
- Result := 64;
- dclVT500:
- Result := 65;
- else
- Result := -1;
- end;
- end;
- function GetSGRString: string;
- begin
- Result := '0';
- if rfBold in FAttribute.RenditionFlags then
- Result := Result + ';1';
- if rfFaint in FAttribute.RenditionFlags then
- Result := Result + ';2';
- if rfItalicized in FAttribute.RenditionFlags then
- Result := Result + ';3';
- if rfUnderlined in FAttribute.RenditionFlags then
- Result := Result + ';4';
- if rfBlinkSlow in FAttribute.RenditionFlags then
- Result := Result + ';5';
- if rfBlinkFast in FAttribute.RenditionFlags then
- Result := Result + ';6';
- if rfInverse in FAttribute.RenditionFlags then
- Result := Result + ';7';
- if rfInvisible in FAttribute.RenditionFlags then
- Result := Result + ';8';
- if rfCrossedOut in FAttribute.RenditionFlags then
- Result := Result + ';9';
- if rfDoublyUnderlined in FAttribute.RenditionFlags then
- Result := Result + ';21';
- case FAttribute.ForegroundColor of
- cDefaultForeground,
- cDefaultBackground:
- ;
- cBlack:
- Result := Result + ';30';
- cRed:
- Result := Result + ';31';
- cGreen:
- Result := Result + ';32';
- cBrown:
- Result := Result + ';33';
- cBlue:
- Result := Result + ';34';
- cMagenta:
- Result := Result + ';35';
- cCyan:
- Result := Result + ';36';
- cLightGray:
- Result := Result + ';37';
- cDarkGray:
- Result := Result + ';90';
- cLightRed:
- Result := Result + ';91';
- cLightGreen:
- Result := Result + ';92';
- cYellow:
- Result := Result + ';93';
- cLightBlue:
- Result := Result + ';94';
- cLightMagenta:
- Result := Result + ';95';
- cLightCyan:
- Result := Result + ';96';
- cWhite:
- Result := Result + ';97';
- cColor16..cColor255:
- Result := Result + ';38:5:' + IntToStr(Ord(FAttribute.ForegroundColor) - (Ord(cColor16) - 16));
- end;
- case FAttribute.BackgroundColor of
- cDefaultForeground,
- cDefaultBackground:
- ;
- cBlack:
- Result := Result + ';40';
- cRed:
- Result := Result + ';41';
- cGreen:
- Result := Result + ';42';
- cBrown:
- Result := Result + ';43';
- cBlue:
- Result := Result + ';44';
- cMagenta:
- Result := Result + ';45';
- cCyan:
- Result := Result + ';46';
- cLightGray:
- Result := Result + ';47';
- cDarkGray:
- Result := Result + ';100';
- cLightRed:
- Result := Result + ';101';
- cLightGreen:
- Result := Result + ';102';
- cYellow:
- Result := Result + ';103';
- cLightBlue:
- Result := Result + ';104';
- cLightMagenta:
- Result := Result + ';105';
- cLightCyan:
- Result := Result + ';106';
- cWhite:
- Result := Result + ';107';
- cColor16..cColor255:
- Result := Result + ';48:5:' + IntToStr(Ord(FAttribute.BackgroundColor) - (Ord(cColor16) - 16));
- end;
- end;
- begin
- case ReqStr of
- 'm':
- TransmitStr(EncodeReturnC1(C1_DCS) + '1$r' + GetSGRString + ReqStr + EncodeReturnC1(C1_ST));
- '"p':
- begin
- if FDecConformanceLevel >= dclVT200 then
- TransmitStr(EncodeReturnC1(C1_DCS) + '1$r' + IntToStr(ConformanceLevel2ID) + ';' + IntToStr(IfThen(tmfSend8BitC1Controls in ModeFlags, 0, 1)) + ReqStr + EncodeReturnC1(C1_ST));
- end;
- 'r':
- TransmitStr(EncodeReturnC1(C1_DCS) + '1$r' + IntToStr(FScrollingRegionTop + 1) + ';' + IntToStr(FScrollingRegionBottom + 1) + ReqStr + EncodeReturnC1(C1_ST));
- 's':
- if FDecConformanceLevel >= dclVT400 then
- TransmitStr(EncodeReturnC1(C1_DCS) + '1$r' + IntToStr(FScrollingRegionLeft + 1) + ';' + IntToStr(FScrollingRegionRight + 1) + ReqStr + EncodeReturnC1(C1_ST))
- else
- TransmitStr(EncodeReturnC1(C1_DCS) + '0$r' + EncodeReturnC1(C1_ST));
- else
- begin
- FLogger.LogMessage(vlWarning, 'Unknown/unsupported DECRQSS: ' + ReqStr);
- TransmitStr(EncodeReturnC1(C1_DCS) + '0$r' + EncodeReturnC1(C1_ST));
- end;
- end;
- end;
- procedure TTerminalController.HandleSGRAttribute(SGRAttr: string);
- var
- ExtPara1, ExtPara2: LongInt;
- ExtParas: TStringArray;
- begin
- if SGRAttr = '' then
- SGRAttr := '0';
- if OnlyDigits(SGRAttr) then
- begin
- case StrToInt(SGRAttr) of
- 0: { Normal (default), VT100 }
- FAttribute := DefaultAttribute;
- 1: { Bold, VT100 }
- FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfBold]) - [rfFaint];
- 2: { Faint, decreased intensity, ECMA-48 2nd }
- FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfFaint]) - [rfBold];
- 3: { Italicized, ECMA-48 2nd }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags + [rfItalicized];
- 4: { Underlined, VT100 }
- FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfUnderlined]) - [rfDoublyUnderlined];
- 5: { slowly blinking (less than 150 per minute), VT100, ECMA-48 2nd }
- FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfBlinkSlow]) - [rfBlinkFast];
- 6: { rapidly blinking (150 per minute or more), ECMA-48 2nd }
- FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfBlinkFast]) - [rfBlinkSlow];
- 7: { negative image }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags + [rfInverse];
- 8: { Invisible, i.e., hidden, ECMA-48 2nd, VT300 }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags + [rfInvisible];
- 9: { Crossed-out characters, ECMA-48 3rd }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags + [rfCrossedOut];
- 21: { Doubly-underlined, ECMA-48 3rd }
- FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfDoublyUnderlined]) - [rfUnderlined];
- 22: { Normal (neither bold nor faint), ECMA-48 3rd }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfBold, rfFaint];
- 23: { Not italicized, ECMA-48 3rd }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfItalicized];
- 24: { Not underlined, ECMA-48 3rd }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfUnderlined, rfDoublyUnderlined];
- 25: { steady (not blinking), ECMA-48 3rd }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfBlinkSlow, rfBlinkFast];
- 27: { positive (not inverse) }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfInverse];
- 28: { Visible, i.e., not hidden, ECMA-48 3rd, VT300 }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfInvisible];
- 29: { Not crossed-out, ECMA-48 3rd }
- FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfCrossedOut];
- 30: { Set foreground color to Black }
- FAttribute.ForegroundColor := cBlack;
- 31: { Set foreground color to Red }
- FAttribute.ForegroundColor := cRed;
- 32: { Set foreground color to Green }
- FAttribute.ForegroundColor := cGreen;
- 33: { Set foreground color to Yellow }
- FAttribute.ForegroundColor := cBrown;
- 34: { Set foreground color to Blue }
- FAttribute.ForegroundColor := cBlue;
- 35: { Set foreground color to Magenta }
- FAttribute.ForegroundColor := cMagenta;
- 36: { Set foreground color to Cyan }
- FAttribute.ForegroundColor := cCyan;
- 37: { Set foreground color to White }
- FAttribute.ForegroundColor := cLightGray;
- 39: { Set foreground color to default, ECMA-48 3rd }
- FAttribute.ForegroundColor := cDefaultForeground;
- 40: { Set background color to Black }
- FAttribute.BackgroundColor := cBlack;
- 41: { Set background color to Red }
- FAttribute.BackgroundColor := cRed;
- 42: { Set background color to Green }
- FAttribute.BackgroundColor := cGreen;
- 43: { Set background color to Yellow }
- FAttribute.BackgroundColor := cBrown;
- 44: { Set background color to Blue }
- FAttribute.BackgroundColor := cBlue;
- 45: { Set background color to Magenta }
- FAttribute.BackgroundColor := cMagenta;
- 46: { Set background color to Cyan }
- FAttribute.BackgroundColor := cCyan;
- 47: { Set background color to White }
- FAttribute.BackgroundColor := cLightGray;
- 49: { Set background color to default, ECMA-48 3rd }
- FAttribute.BackgroundColor := cDefaultBackground;
- 90: { Set foreground color to Black }
- FAttribute.ForegroundColor := cDarkGray;
- 91: { Set foreground color to Red }
- FAttribute.ForegroundColor := cLightRed;
- 92: { Set foreground color to Green }
- FAttribute.ForegroundColor := cLightGreen;
- 93: { Set foreground color to Yellow }
- FAttribute.ForegroundColor := cYellow;
- 94: { Set foreground color to Blue }
- FAttribute.ForegroundColor := cLightBlue;
- 95: { Set foreground color to Magenta }
- FAttribute.ForegroundColor := cLightMagenta;
- 96: { Set foreground color to Cyan }
- FAttribute.ForegroundColor := cLightCyan;
- 97: { Set foreground color to White }
- FAttribute.ForegroundColor := cWhite;
- 100: { Set background color to Black }
- FAttribute.BackgroundColor := cDarkGray;
- 101: { Set background color to Red }
- FAttribute.BackgroundColor := cLightRed;
- 102: { Set background color to Green }
- FAttribute.BackgroundColor := cLightGreen;
- 103: { Set background color to Yellow }
- FAttribute.BackgroundColor := cYellow;
- 104: { Set background color to Blue }
- FAttribute.BackgroundColor := cLightBlue;
- 105: { Set background color to Magenta }
- FAttribute.BackgroundColor := cLightMagenta;
- 106: { Set background color to Cyan }
- FAttribute.BackgroundColor := cLightCyan;
- 107: { Set background color to White }
- FAttribute.BackgroundColor := cWhite;
- else
- FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
- end;
- end
- else
- begin
- if Pos(':', SGRAttr) <> 0 then
- begin
- ExtParas := SGRAttr.Split(':');
- ExtPara1 := StrToIntDef(ExtParas[0], 0);
- case ExtPara1 of
- 38,
- 48:
- begin
- ExtPara2 := StrToIntDef(ExtParas[1], 0);
- case ExtPara2 of
- 2:
- begin
- if Length(ExtParas) = 5 then
- begin
- if ExtPara1 = 38 then
- FAttribute.SetForegroundColorRGB(StrToIntDef(ExtParas[2], 0), StrToIntDef(ExtParas[3], 0), StrToIntDef(ExtParas[4], 0))
- else if ExtPara1 = 48 then
- FAttribute.SetBackgroundColorRGB(StrToIntDef(ExtParas[2], 0), StrToIntDef(ExtParas[3], 0), StrToIntDef(ExtParas[4], 0));
- end
- else if Length(ExtParas) >= 6 then
- begin
- if ExtPara1 = 38 then
- FAttribute.SetForegroundColorRGB(StrToIntDef(ExtParas[3], 0), StrToIntDef(ExtParas[4], 0), StrToIntDef(ExtParas[5], 0))
- else if ExtPara1 = 48 then
- FAttribute.SetBackgroundColorRGB(StrToIntDef(ExtParas[3], 0), StrToIntDef(ExtParas[4], 0), StrToIntDef(ExtParas[5], 0));
- end
- else
- FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
- end;
- 5:
- begin
- if ExtPara1 = 38 then
- FAttribute.ForegroundColor := TColor(StrToIntDef(ExtParas[2], 0))
- else if ExtPara1 = 48 then
- FAttribute.BackgroundColor := TColor(StrToIntDef(ExtParas[2], 0));
- end;
- else
- FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
- end;
- end;
- else
- FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
- end;
- end
- else
- FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
- end;
- end;
- procedure TTerminalController.ScrollUp(LinesCount: Integer);
- var
- X, Y: Integer;
- begin
- if LinesCount < 0 then
- exit;
- if LinesCount = 0 then
- LinesCount := 1;
- for Y := FScrollingRegionTop to FScrollingRegionBottom - LinesCount do
- for X := FScrollingRegionLeft to FScrollingRegionRight do
- FModel.Cell[Y, X] := FModel.Cell[Y + LinesCount, X];
- for Y := Max(FScrollingRegionBottom - LinesCount + 1, FScrollingRegionTop) to FScrollingRegionBottom do
- for X := FScrollingRegionLeft to FScrollingRegionRight do
- FModel.Cell[Y, X] := ErasedCell(FAttribute);
- end;
- procedure TTerminalController.ScrollDown(LinesCount: Integer);
- var
- X, Y: Integer;
- begin
- if LinesCount < 0 then
- exit;
- if LinesCount = 0 then
- LinesCount := 1;
- for Y := FScrollingRegionBottom downto FScrollingRegionTop + LinesCount do
- for X := FScrollingRegionLeft to FScrollingRegionRight do
- FModel.Cell[Y, X] := FModel.Cell[Y - LinesCount, X];
- for Y := FScrollingRegionTop to Min(FScrollingRegionTop + LinesCount - 1, FScrollingRegionBottom) do
- for X := FScrollingRegionLeft to FScrollingRegionRight do
- FModel.Cell[Y, X] := ErasedCell(FAttribute);
- end;
- procedure TTerminalController.ScrollLeft(CharCount: Integer);
- var
- Y, X: Integer;
- begin
- if CharCount < 0 then
- exit;
- if CharCount = 0 then
- CharCount := 1;
- for Y := FScrollingRegionTop to FScrollingRegionBottom do
- begin
- for X := 0 to FModel.Width - CharCount - 1 do
- FModel.Cell[Y, X] := FModel.Cell[Y, X + CharCount];
- for X := Max(0, FModel.Width - CharCount) to FModel.Width - 1 do
- FModel.Cell[Y, X] := ErasedCell(FAttribute);
- end;
- end;
- procedure TTerminalController.ScrollRight(CharCount: Integer);
- var
- Y, X: Integer;
- begin
- if CharCount < 0 then
- exit;
- if CharCount = 0 then
- CharCount := 1;
- for Y := FScrollingRegionTop to FScrollingRegionBottom do
- begin
- for X := FModel.Width - 1 downto CharCount do
- FModel.Cell[Y, X] := FModel.Cell[Y, X - CharCount];
- for X := 0 to Min(CharCount - 1, FModel.Width - 1) do
- FModel.Cell[Y, X] := ErasedCell(FAttribute);
- end;
- end;
- procedure TTerminalController.InsertLines(LinesCount: Integer);
- var
- X, Y: Integer;
- begin
- if LinesCount < 0 then
- exit;
- if LinesCount = 0 then
- LinesCount := 1;
- if LinesCount > (FScrollingRegionBottom - FModel.CursorY + 1) then
- LinesCount := FScrollingRegionBottom - FModel.CursorY + 1;
- for Y := FScrollingRegionBottom downto FModel.CursorY + LinesCount do
- for X := 0 to FModel.Width - 1 do
- FModel.Cell[Y, X] := FModel.Cell[Y - LinesCount, X];
- for Y := FModel.CursorY to FModel.CursorY + LinesCount - 1 do
- for X := 0 to FModel.Width - 1 do
- FModel.Cell[Y, X] := ErasedCell(FAttribute);
- FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
- end;
- procedure TTerminalController.DeleteLines(LinesCount: Integer);
- var
- X, Y: Integer;
- begin
- if LinesCount < 0 then
- exit;
- if LinesCount = 0 then
- LinesCount := 1;
- if LinesCount > (FScrollingRegionBottom - FModel.CursorY + 1) then
- LinesCount := FScrollingRegionBottom - FModel.CursorY + 1;
- for Y := FModel.CursorY to FScrollingRegionBottom - LinesCount do
- for X := 0 to FModel.Width - 1 do
- FModel.Cell[Y, X] := FModel.Cell[Y + LinesCount, X];
- for Y := FScrollingRegionBottom - LinesCount + 1 to FScrollingRegionBottom do
- for X := 0 to FModel.Width - 1 do
- FModel.Cell[Y, X] := ErasedCell(FAttribute);
- FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
- end;
- procedure TTerminalController.DeleteCharacters(CharCount: Integer);
- var
- X: Integer;
- begin
- for X := FModel.CursorX to FModel.Width - 1 do
- if (X + CharCount) < FModel.Width then
- FModel.Cell[FModel.CursorY, X] := FModel.Cell[FModel.CursorY, X + CharCount]
- else
- FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
- FNextCharacterWrapsToNextLine := False;
- end;
- procedure TTerminalController.ErasePage;
- var
- X, Y: Integer;
- begin
- for Y := 0 to FModel.Height - 1 do
- for X := 0 to FModel.Width - 1 do
- FModel.Cell[Y, X] := ErasedCell(FAttribute);
- FNextCharacterWrapsToNextLine := False;
- end;
- procedure TTerminalController.ErasePageToBottom;
- var
- X, Y: Integer;
- begin
- for X := FModel.CursorX to FModel.Width - 1 do
- FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
- for Y := FModel.CursorY + 1 to FModel.Height - 1 do
- for X := 0 to FModel.Width - 1 do
- FModel.Cell[Y, X] := ErasedCell(FAttribute);
- FNextCharacterWrapsToNextLine := False;
- end;
- procedure TTerminalController.ErasePageToTop;
- var
- X, Y: Integer;
- begin
- for X := 0 to FModel.CursorX do
- FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
- for Y := 0 to FModel.CursorY - 1 do
- for X := 0 to FModel.Width - 1 do
- FModel.Cell[Y, X] := ErasedCell(FAttribute);
- FNextCharacterWrapsToNextLine := False;
- end;
- procedure TTerminalController.EraseLineToRight;
- var
- X: Integer;
- begin
- for X := FModel.CursorX to FModel.Width - 1 do
- FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
- FNextCharacterWrapsToNextLine := False;
- end;
- procedure TTerminalController.EraseLineToLeft;
- var
- X: Integer;
- begin
- for X := 0 to FModel.CursorX do
- FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
- FNextCharacterWrapsToNextLine := False;
- end;
- procedure TTerminalController.EraseLine;
- var
- X: Integer;
- begin
- for X := 0 to FModel.Width - 1 do
- FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
- FNextCharacterWrapsToNextLine := False;
- end;
- procedure TTerminalController.EraseCharacters(CharCount: Integer);
- var
- X: Integer;
- begin
- if CharCount < 0 then
- exit;
- if CharCount = 0 then
- CharCount := 1;
- for X := FModel.CursorX to Min(FModel.CursorX + CharCount - 1, FModel.Width - 1) do
- FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
- FNextCharacterWrapsToNextLine := False;
- end;
- procedure TTerminalController.InsertBlankCharacters(CharCount: Integer);
- var
- X: Integer;
- begin
- if CharCount < 0 then
- exit;
- if CharCount = 0 then
- CharCount := 1;
- for X := FModel.Width - 1 downto FModel.CursorX + CharCount do
- FModel.Cell[FModel.CursorY, X] := FModel.Cell[FModel.CursorY, X - CharCount];
- for X := FModel.CursorX to Min(FModel.CursorX + CharCount - 1, FModel.Width - 1) do
- FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
- FNextCharacterWrapsToNextLine := False;
- end;
- procedure TTerminalController.WriteUTF32Char(const UTF32Char: LongWord);
- var
- SaveLastGraphicCharacter: TExtendedGraphemeCluster;
- X: Integer;
- begin
- SaveLastGraphicCharacter := FLastGraphicCharacter;
- FLastGraphicCharacter := '';
- if (UTF32Char >= $D800) and (UTF32Char <= $DFFF) then
- { error }
- exit
- else if UTF32Char <= $FFFF then
- FLastGraphicCharacter := WideChar(UTF32Char)
- else if UTF32Char <= $10FFFF then
- FLastGraphicCharacter := WideChar(((UTF32Char - $10000) shr 10) + $D800) + WideChar(((UTF32Char - $10000) and %1111111111) + $DC00)
- else
- { error }
- exit;
- if (SaveLastGraphicCharacter <> '') and (FModel.StringDisplayWidth(SaveLastGraphicCharacter + FLastGraphicCharacter) <= 1) then
- begin
- { combine with previous character }
- FLastGraphicCharacter := SaveLastGraphicCharacter + FLastGraphicCharacter;
- if FNextCharacterWrapsToNextLine then
- FModel.Cell[FModel.CursorY, FModel.CursorX] := Cell(FLastGraphicCharacter, FAttribute)
- else
- FModel.Cell[FModel.CursorY, FModel.CursorX - 1] := Cell(FLastGraphicCharacter, FAttribute);
- end
- else
- begin
- { type a new character }
- if FNextCharacterWrapsToNextLine then
- begin
- FNextCharacterWrapsToNextLine := False;
- if FModel.CursorY >= FScrollingRegionBottom then
- begin
- ScrollUp;
- FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
- end
- else
- FModel.SetCursorPos(CursorHomeX, FModel.CursorY + 1);
- end;
- if tmfInsertMode in FModeFlags then
- for X := FModel.Width - 1 downto FModel.CursorX + 1 do
- FModel.Cell[FModel.CursorY, X] := FModel.Cell[FModel.CursorY, X - 1];
- FModel.Cell[FModel.CursorY, FModel.CursorX] := Cell(FLastGraphicCharacter, FAttribute);
- if FModel.CursorX >= (FModel.Width - 1) then
- begin
- if tmfAutoWrapMode in FModeFlags then
- FNextCharacterWrapsToNextLine := True;
- end
- else
- FModel.SetCursorPos(FModel.CursorX + 1, FModel.CursorY);
- end;
- end;
- procedure TTerminalController.WriteVT100CharFromCharset(Ch: Char;
- Charset: TDecCharacterSet);
- begin
- Ch := Chr(Ord(Ch) and $7F);
- if (Ch = #127) and not (Charset in CharacterSets96) then
- exit;
- case Charset of
- dcsUSASCII:
- WriteUTF32Char(Ord(Ch));
- dcsBritishNRCS:
- if Ch = '#' then
- WriteUTF32Char($00A3)
- else
- WriteUTF32Char(Ord(Ch));
- dcsFinnishNRCS:
- case Ch of
- #$5B:
- WriteUTF32Char($00C4);
- #$5C:
- WriteUTF32Char($00D6);
- #$5D:
- WriteUTF32Char($00C5);
- #$5E:
- WriteUTF32Char($00DC);
- #$60:
- WriteUTF32Char($00E9);
- #$7B:
- WriteUTF32Char($00E4);
- #$7C:
- WriteUTF32Char($00F6);
- #$7D:
- WriteUTF32Char($00E5);
- #$7E:
- WriteUTF32Char($00FC);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsSwedishNRCS:
- case Ch of
- #$40:
- WriteUTF32Char($00C9);
- #$5B:
- WriteUTF32Char($00C4);
- #$5C:
- WriteUTF32Char($00D6);
- #$5D:
- WriteUTF32Char($00C5);
- #$5E:
- WriteUTF32Char($00DC);
- #$60:
- WriteUTF32Char($00E9);
- #$7B:
- WriteUTF32Char($00E4);
- #$7C:
- WriteUTF32Char($00F6);
- #$7D:
- WriteUTF32Char($00E5);
- #$7E:
- WriteUTF32Char($00FC);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsGermanNRCS:
- case Ch of
- #$40:
- WriteUTF32Char($00A7);
- #$5B:
- WriteUTF32Char($00C4);
- #$5C:
- WriteUTF32Char($00D6);
- #$5D:
- WriteUTF32Char($00DC);
- #$7B:
- WriteUTF32Char($00E4);
- #$7C:
- WriteUTF32Char($00F6);
- #$7D:
- WriteUTF32Char($00FC);
- #$7E:
- WriteUTF32Char($00DF);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsFrenchCanadianNRCS:
- case Ch of
- #$40:
- WriteUTF32Char($00E0);
- #$5B:
- WriteUTF32Char($00E2);
- #$5C:
- WriteUTF32Char($00E7);
- #$5D:
- WriteUTF32Char($00EA);
- #$5E:
- WriteUTF32Char($00EE);
- #$60:
- WriteUTF32Char($00F4);
- #$7B:
- WriteUTF32Char($00E9);
- #$7C:
- WriteUTF32Char($00F9);
- #$7D:
- WriteUTF32Char($00E8);
- #$7E:
- WriteUTF32Char($00FB);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsFrenchNRCS:
- case Ch of
- #$23:
- WriteUTF32Char($00A3);
- #$40:
- WriteUTF32Char($00E0);
- #$5B:
- WriteUTF32Char($00B0);
- #$5C:
- WriteUTF32Char($00E7);
- #$5D:
- WriteUTF32Char($00A7);
- #$7B:
- WriteUTF32Char($00E9);
- #$7C:
- WriteUTF32Char($00F9);
- #$7D:
- WriteUTF32Char($00E8);
- #$7E:
- WriteUTF32Char($00A8);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsItalianNRCS:
- case Ch of
- #$23:
- WriteUTF32Char($00A3);
- #$40:
- WriteUTF32Char($00A7);
- #$5B:
- WriteUTF32Char($00B0);
- #$5C:
- WriteUTF32Char($00E7);
- #$5D:
- WriteUTF32Char($00E9);
- #$60:
- WriteUTF32Char($00F9);
- #$7B:
- WriteUTF32Char($00E0);
- #$7C:
- WriteUTF32Char($00F2);
- #$7D:
- WriteUTF32Char($00E8);
- #$7E:
- WriteUTF32Char($00EC);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsSpanishNRCS:
- case Ch of
- #$23:
- WriteUTF32Char($00A3);
- #$40:
- WriteUTF32Char($00A7);
- #$5B:
- WriteUTF32Char($00A1);
- #$5C:
- WriteUTF32Char($00D1);
- #$5D:
- WriteUTF32Char($00BF);
- #$7B:
- WriteUTF32Char($00B0);
- #$7C:
- WriteUTF32Char($00F1);
- #$7D:
- WriteUTF32Char($00E7);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsDutchNRCS:
- case Ch of
- #$23:
- WriteUTF32Char($00A3);
- #$40:
- WriteUTF32Char($00BE);
- #$5B:
- WriteUTF32Char($0133);
- #$5C:
- WriteUTF32Char($00BD);
- #$5D:
- WriteUTF32Char($007C);
- #$7B:
- WriteUTF32Char($00A8);
- #$7C:
- WriteUTF32Char($0192);
- #$7D:
- WriteUTF32Char($00BC);
- #$7E:
- WriteUTF32Char($00B4);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsSwissNRCS:
- case Ch of
- #$23:
- WriteUTF32Char($00F9);
- #$40:
- WriteUTF32Char($00E0);
- #$5B:
- WriteUTF32Char($00E9);
- #$5C:
- WriteUTF32Char($00E7);
- #$5D:
- WriteUTF32Char($00EA);
- #$5E:
- WriteUTF32Char($00EE);
- #$5F:
- WriteUTF32Char($00E8);
- #$60:
- WriteUTF32Char($00F4);
- #$7B:
- WriteUTF32Char($00E4);
- #$7C:
- WriteUTF32Char($00F6);
- #$7D:
- WriteUTF32Char($00FC);
- #$7E:
- WriteUTF32Char($00FB);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsNorwegianDanishNRCS:
- case Ch of
- #$40:
- WriteUTF32Char($00C4);
- #$5B:
- WriteUTF32Char($00C6);
- #$5C:
- WriteUTF32Char($00D8);
- #$5D:
- WriteUTF32Char($00C5);
- #$5E:
- WriteUTF32Char($00DC);
- #$60:
- WriteUTF32Char($00E4);
- #$7B:
- WriteUTF32Char($00E6);
- #$7C:
- WriteUTF32Char($00F8);
- #$7D:
- WriteUTF32Char($00E5);
- #$7E:
- WriteUTF32Char($00FC);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsPortugueseNRCS:
- case Ch of
- #$5B:
- WriteUTF32Char($00C3);
- #$5C:
- WriteUTF32Char($00C7);
- #$5D:
- WriteUTF32Char($00D5);
- #$7B:
- WriteUTF32Char($00E3);
- #$7C:
- WriteUTF32Char($00E7);
- #$7D:
- WriteUTF32Char($00F5);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsGreekNRCS:
- case Ch of
- 'n':
- WriteUTF32Char($03A7);
- 'v':
- WriteUTF32Char($039E);
- 'a'..'m', 'o'..'q':
- WriteUTF32Char(Ord(Ch) + ($0391 - Ord('a')));
- 'r'..'u', 'w'..'x':
- WriteUTF32Char(Ord(Ch) + ($0392 - Ord('a')));
- 'y'..'z':
- WriteUTF32Char($0020);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsTurkishNRCS:
- case Ch of
- '&':
- WriteUTF32Char($011F);
- #$40:
- WriteUTF32Char($0130);
- #$5B:
- WriteUTF32Char($015E);
- #$5C:
- WriteUTF32Char($00D6);
- #$5D:
- WriteUTF32Char($00C7);
- #$5E:
- WriteUTF32Char($00DC);
- #$60:
- WriteUTF32Char($011E);
- #$7B:
- WriteUTF32Char($015F);
- #$7C:
- WriteUTF32Char($00F6);
- #$7D:
- WriteUTF32Char($00E7);
- #$7E:
- WriteUTF32Char($00FC);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsHebrewNRCS:
- case Ch of
- #$60..#$7A:
- WriteUTF32Char(Ord(Ch) + ($05D0 - $60));
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsDecHebrew:
- case Ch of
- '!'..'''', ')', '+'..'9', ';'..'?':
- WriteVT100CharFromCharset(Ch, dcsDecSupplemental);
- '(':
- WriteUTF32Char($00A8);
- '*':
- WriteUTF32Char($00D7);
- ':':
- WriteUTF32Char($00F7);
- #$60..#$7A:
- WriteUTF32Char(Ord(Ch) + ($05D0 - $60));
- '@'..'_', '{'..'~':
- WriteUTF32Char($FFFD);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsDecGreek:
- case Ch of
- '!'..'?':
- WriteVT100CharFromCharset(Ch, dcsDecSupplemental);
- '@':
- WriteUTF32Char($03CA);
- 'A'..'O':
- WriteUTF32Char(Ord(Ch) + ($0391 - Ord('A')));
- 'P':
- WriteUTF32Char($FFFD);
- 'Q'..'R':
- WriteUTF32Char(Ord(Ch) + ($03A0 - Ord('Q')));
- 'S'..'Y':
- WriteUTF32Char(Ord(Ch) + ($03A3 - Ord('S')));
- 'Z'..']':
- WriteUTF32Char(Ord(Ch) + ($03AC - Ord('Z')));
- '^':
- WriteUTF32Char($FFFD);
- '_':
- WriteUTF32Char($03CC);
- '`':
- WriteUTF32Char($03CB);
- 'a'..'o':
- WriteUTF32Char(Ord(Ch) + ($03B1 - Ord('a')));
- 'p':
- WriteUTF32Char($FFFD);
- 'q'..'r':
- WriteUTF32Char(Ord(Ch) + ($03C0 - Ord('q')));
- 's'..'y':
- WriteUTF32Char(Ord(Ch) + ($03C3 - Ord('s')));
- 'z':
- WriteUTF32Char($03C2);
- '{':
- WriteUTF32Char($03CD);
- '|':
- WriteUTF32Char($03CE);
- '}':
- WriteUTF32Char($0384);
- '~':
- WriteUTF32Char($FFFD);
- else
- WriteUTF32Char(Ord(Ch));
- end;
- dcsDecTurkish:
- case Ch of
- '(':
- WriteUTF32Char($00A8);
- '.':
- WriteUTF32Char($0130);
- '>':
- WriteUTF32Char($0131);
- 'P':
- WriteUTF32Char($011E);
- '^':
- WriteUTF32Char($015E);
- 'p':
- WriteUTF32Char($011F);
- '~':
- WriteUTF32Char($015F);
- else
- WriteVT100CharFromCharset(Ch, dcsDecSupplemental);
- end;
- dcsDecCyrillic:
- if (Ch >= Low(DecCyrillicCharacterSet)) and (Ch <= High(DecCyrillicCharacterSet)) then
- WriteUTF32Char(DecCyrillicCharacterSet[Ch])
- else
- WriteUTF32Char($FFFD);
- dcsDecSpecialGraphics:
- if (Ch >= Low(DecSpecialGraphicsCharacterSet)) and (Ch <= High(DecSpecialGraphicsCharacterSet)) then
- WriteUTF32Char(DecSpecialGraphicsCharacterSet[Ch])
- else
- WriteUTF32Char(Ord(Ch));
- dcsDecTechnical:
- if (Ch >= Low(DecTechnicalCharacterSet)) and (Ch <= High(DecTechnicalCharacterSet)) then
- WriteUTF32Char(DecTechnicalCharacterSet[Ch])
- else
- WriteUTF32Char(Ord(Ch));
- dcsDecSupplemental:
- case Ch of
- Chr($A8 - $80):
- WriteUTF32Char($00A4);
- Chr($D7 - $80):
- WriteUTF32Char($0152);
- Chr($DD - $80):
- WriteUTF32Char($0178);
- Chr($F7 - $80):
- WriteUTF32Char($0153);
- Chr($FD - $80):
- WriteUTF32Char($00FF);
- Chr($A4 - $80),
- Chr($A6 - $80),
- Chr($AC - $80)..Chr($AF - $80),
- Chr($B4 - $80),
- Chr($B8 - $80),
- Chr($BE - $80),
- Chr($D0 - $80),
- Chr($DE - $80),
- Chr($F0 - $80),
- Chr($FE - $80):
- { REPLACEMENT CHARACTER }
- WriteUTF32Char($FFFD);
- #0..#32,#127:
- WriteUTF32Char(Ord(Ch));
- else
- WriteUTF32Char(Ord(Ch) + $80);
- end;
- dcsISOLatin1Supplemental:
- WriteUTF32Char(Ord(Ch) + $80);
- end;
- end;
- procedure TTerminalController.WriteVT100Char(Ch: Char);
- begin
- if Ord(Ch) <= 127 then
- WriteVT100CharFromCharset(Ch, FGCharacterSets[FGLCharacterSet])
- else
- WriteVT100CharFromCharset(Ch, FGCharacterSets[FGRCharacterSet]);
- end;
- procedure TTerminalController.WriteVT52Char(Ch: Char);
- begin
- Ch := Chr(Ord(Ch) and 127);
- case FVT52CharacterSet of
- v52csASCII:
- WriteUTF32Char(Ord(Ch));
- v52csGraphics:
- if (Ch >= Low(VT52GraphicsCharacterSet)) and (Ch <= High(VT52GraphicsCharacterSet)) then
- WriteUTF32Char(VT52GraphicsCharacterSet[Ch])
- else
- WriteUTF32Char(Ord(Ch));
- end;
- end;
- procedure TTerminalController.WriteRepeatedCharacter(const EGC: TExtendedGraphemeCluster; Count: Integer);
- var
- I, J: Integer;
- begin
- for I := 1 to Count do
- begin
- J := 1;
- while J <= Length(EGC) do
- begin
- if (EGC[J] >= #$D800) and (EGC[J] <= #$DFFF) then
- begin
- if (EGC[J] < #$DC00) and (J < Length(EGC)) and (EGC[J + 1] >= #$DC00) and (EGC[J + 1] <= #$DFFF) then
- begin
- WriteUTF32Char($10000 + ((LongWord(EGC[J]) - $D800) shl 10) + (LongWord(EGC[J + 1]) - $DC00));
- Inc(J, 2);
- end
- else
- { invalid UTF-16 code unit, skip it }
- Inc(J);
- end
- else
- WriteUTF32Char(LongWord(EGC[J]));
- Inc(J);
- end;
- end;
- end;
- procedure TTerminalController.HandleC1(Ch: TC1Char);
- begin
- case Ch of
- C1_CSI:
- begin
- FState := tsmsCSI;
- ClearControlSequence;
- end;
- C1_OSC:
- begin
- FState := tsmsOSC;
- FOperatingSystemCommand := '';
- end;
- C1_DCS:
- begin
- FState := tsmsDCS;
- FDeviceControlString := '';
- end;
- C1_RI:
- begin
- FNextCharacterWrapsToNextLine := False;
- FState := tsmsInitial;
- if FModel.CursorY = 0 then
- begin
- ScrollDown;
- FModel.SetCursorPos(FModel.CursorX, FModel.CursorY);
- end
- else
- FModel.SetCursorPos(FModel.CursorX, FModel.CursorY - 1);
- end;
- C1_IND:
- begin
- FNextCharacterWrapsToNextLine := False;
- FState := tsmsInitial;
- if FModel.CursorY >= FScrollingRegionBottom then
- begin
- ScrollUp;
- FModel.SetCursorPos(FModel.CursorX, FModel.CursorY);
- end
- else
- FModel.SetCursorPos(FModel.CursorX, FModel.CursorY + 1);
- end;
- C1_NEL:
- begin
- FNextCharacterWrapsToNextLine := False;
- FState := tsmsInitial;
- if FModel.CursorY >= FScrollingRegionBottom then
- begin
- ScrollUp;
- FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
- end
- else
- FModel.SetCursorPos(CursorHomeX, FModel.CursorY + 1);
- end;
- C1_HTS:
- begin
- FState := tsmsInitial;
- FTabStops[FModel.CursorX] := True;
- end
- else
- { error }
- FLogger.LogMessage(vlWarning, 'Unhandled C1 character: #' + IntToStr(Ord(Ch)));
- FState := tsmsInitial;
- end;
- end;
- procedure TTerminalController.HandleENQ;
- begin
- TransmitStr(VT100AnswerbackString);
- end;
- procedure TTerminalController.HandleCR;
- begin
- FNextCharacterWrapsToNextLine := False;
- FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
- end;
- procedure TTerminalController.HandleLF;
- begin
- FNextCharacterWrapsToNextLine := False;
- if FModel.CursorY >= FScrollingRegionBottom then
- begin
- ScrollUp;
- FModel.SetCursorPos(FModel.CursorX, FModel.CursorY);
- end
- else
- FModel.SetCursorPos(FModel.CursorX, FModel.CursorY + 1);
- if tmfAutoNewLine in ModeFlags then
- FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
- end;
- procedure TTerminalController.HandleBS;
- begin
- FNextCharacterWrapsToNextLine := False;
- if FModel.CursorX > 0 then
- FModel.SetCursorPos(FModel.CursorX - 1, FModel.CursorY);
- end;
- procedure TTerminalController.HandleHT;
- begin
- CursorForwardTabulation(1);
- end;
- procedure TTerminalController.CursorForwardTabulation(TabStops: Integer);
- var
- CX: Integer;
- begin
- if TabStops < 0 then
- exit;
- if TabStops = 0 then
- TabStops := 1;
- CX := FModel.CursorX;
- while (TabStops > 0) and (CX < (FModel.Width - 1)) do
- begin
- Dec(TabStops);
- repeat
- if CX < (FModel.Width - 1) then
- Inc(CX);
- until FTabStops[CX] or (CX >= (FModel.Width - 1));
- end;
- FModel.SetCursorPos(CX, FModel.CursorY);
- end;
- procedure TTerminalController.CursorBackwardTabulation(TabStops: Integer);
- var
- CX: Integer;
- begin
- if TabStops < 0 then
- exit;
- if TabStops = 0 then
- TabStops := 1;
- CX := FModel.CursorX;
- while (TabStops > 0) and (CX > 0) do
- begin
- Dec(TabStops);
- repeat
- if CX > 0 then
- Dec(CX);
- until FTabStops[CX] or (CX = 0);
- end;
- FModel.SetCursorPos(CX, FModel.CursorY);
- end;
- procedure TTerminalController.EnterVT52Mode;
- begin
- FVT52CharacterSet := v52csASCII;
- FDecConformanceLevel := dclVT52;
- FState := tsmsVT52_Initial;
- end;
- procedure TTerminalController.LeaveVT52Mode;
- begin
- FDecConformanceLevel := dclVT100;
- Exclude(FModeFlags, tmfSend8BitC1Controls);
- FState := tsmsInitial;
- end;
- procedure TTerminalController.TransmitData(const buf; Bytes: SizeUInt);
- begin
- if Assigned(FOnTransmitData) then
- FOnTransmitData(buf, Bytes);
- end;
- procedure TTerminalController.TransmitStr(const S: string);
- begin
- TransmitData(s[1], Length(S));
- end;
- procedure TTerminalController.HardReset;
- begin
- FDecConformanceLevel := MaxConformanceLevelForTerminal[FTerminalType];
- FAttribute := DefaultAttribute;
- FModeFlags := DefaultModeFlags;
- FSavedCursor.Reset;
- FTabStops.Reset;
- { todo: what are the default character sets? }
- FDesignatingCharacterSet := gcsG0;
- FGLCharacterSet := gcsG0;
- FGRCharacterSet := gcsG1;
- FGCharacterSets[gcsG0] := dcsUSASCII;
- FGCharacterSets[gcsG1] := dcsUSASCII;
- FGCharacterSets[gcsG2] := dcsUSASCII;
- FGCharacterSets[gcsG3] := dcsUSASCII;
- FVT52CharacterSet := v52csASCII;
- FOldMouseX := 0;
- FOldMouseY := 0;
- FOldMouseButtons := [];
- FMouseTrackingMode := tmtmNone;
- FMouseProtocolEncoding := tmpeX10;
- FScrollingRegionTop := 0;
- FScrollingRegionBottom := FModel.Height - 1;
- FScrollingRegionLeft := 0;
- FScrollingRegionRight := FModel.Width - 1;
- if FDecConformanceLevel = dclVT52 then
- FState := tsmsVT52_Initial
- else
- FState := tsmsInitial;
- FUTF8_Build := 0;
- ClearControlSequence;
- FOperatingSystemCommand := '';
- FDeviceControlString := '';
- FVT100AnswerbackString := '';
- FLastGraphicCharacter := '';
- FNextCharacterWrapsToNextLine := False;
- FModel.Reset;
- end;
- procedure TTerminalController.SoftReset;
- begin
- FLogger.LogMessage(vlWarning, 'Soft reset not yet implemented');
- end;
- constructor TTerminalController.Create(AModel: TTerminalModel;
- ATerminalType: TTerminalType);
- begin
- FTerminalType := ATerminalType;
- FSavedCursor := TTerminalSavedCursor.Create;
- FLogger := TFileLogger.Create('fpterm.log', DefaultLogLevel);
- FModel := AModel;
- FTabStops := TTerminalTabStops.Create;
- HardReset;
- end;
- destructor TTerminalController.Destroy;
- begin
- FreeAndNil(FSavedCursor);
- FreeAndNil(FTabStops);
- FreeAndNil(FLogger);
- inherited Destroy;
- end;
- function TTerminalController.Resize(NewWidth, NewHeight: Integer): Boolean;
- var
- OldWidth, OldHeight: Integer;
- begin
- OldWidth := FModel.Width;
- OldHeight := FModel.Height;
- if FModel.Resize(NewWidth, NewHeight) then
- begin
- Result := True;
- if FScrollingRegionBottom = (OldHeight - 1) then
- FScrollingRegionBottom := NewHeight - 1
- else if FScrollingRegionBottom > (NewHeight - 1) then
- FScrollingRegionBottom := NewHeight - 1;
- if FScrollingRegionTop > FScrollingRegionBottom then
- FScrollingRegionTop := FScrollingRegionBottom;
- if FScrollingRegionRight = (OldWidth - 1) then
- FScrollingRegionRight := NewWidth - 1
- else if FScrollingRegionRight > (NewWidth - 1) then
- FScrollingRegionRight := NewWidth - 1;
- if FScrollingRegionLeft > FScrollingRegionRight then
- FScrollingRegionLeft := FScrollingRegionRight;
- if Assigned(FOnResize) then
- FOnResize(NewWidth, NewHeight);
- end
- else
- Result := False;
- end;
- procedure TTerminalController.ReceiveData(const buf; Bytes: SizeUInt);
- var
- I: SizeUInt;
- Ch: Char;
- Y, X: Integer;
- begin
- if Bytes <= 0 then
- exit;
- for I := 0 to Bytes - 1 do
- begin
- Ch := PChar(@buf)[I];
- case FState of
- tsmsInitial:
- begin
- case Ch of
- C0_ENQ:
- HandleENQ;
- C0_CR:
- HandleCR;
- C0_VT,
- C0_FF,
- C0_LF:
- HandleLF;
- C0_BS:
- HandleBS;
- C0_HT:
- HandleHT;
- C0_ESC:
- FState := tsmsESC;
- C0_SI:
- FGLCharacterSet := gcsG0;
- C0_SO:
- FGLCharacterSet := gcsG1;
- #32..#127:
- WriteVT100Char(Ch);
- #$80..#$9F:
- HandleC1(Ch);
- #$A0..#$FF:
- begin
- if tmfUTF8Mode in ModeFlags then
- begin
- case Ch of
- #%11000000..#%11011111:
- begin
- FState := tsmsUTF8_1ByteLeft;
- FUTF8_Build := Ord(Ch) and %11111;
- end;
- #%11100000..#%11101111:
- begin
- FState := tsmsUTF8_2BytesLeft;
- FUTF8_Build := Ord(Ch) and %1111;
- end;
- #%11110000..#%11110111:
- begin
- FState := tsmsUTF8_3BytesLeft;
- FUTF8_Build := Ord(Ch) and %111;
- end;
- else
- FLogger.LogMessage(vlWarning, 'Unhandled character: #' + IntToStr(Ord(Ch)));
- end;
- end
- else
- WriteVT100Char(Ch);
- end;
- else
- FLogger.LogMessage(vlWarning, 'Unhandled character: #' + IntToStr(Ord(Ch)));
- end;
- end;
- tsmsESC:
- begin
- case Ch of
- #27:
- FState := tsmsESC;
- #$40..#$5F:
- HandleC1(Chr(Ord(Ch) + $40));
- ' ':
- FState := tsmsESC_SP;
- '#':
- FState := tsmsESC_Hash;
- '%':
- FState := tsmsESC_Percent;
- '(':
- begin
- FState := tsmsDesignateG0123CharacterSet94;
- FDesignatingCharacterSet := gcsG0;
- end;
- ')':
- begin
- FState := tsmsDesignateG0123CharacterSet94;
- FDesignatingCharacterSet := gcsG1;
- end;
- '*':
- begin
- FState := tsmsDesignateG0123CharacterSet94;
- FDesignatingCharacterSet := gcsG2;
- end;
- '+':
- begin
- FState := tsmsDesignateG0123CharacterSet94;
- FDesignatingCharacterSet := gcsG3;
- end;
- '-':
- begin
- FState := tsmsDesignateG0123CharacterSet96;
- FDesignatingCharacterSet := gcsG1;
- end;
- '.':
- begin
- FState := tsmsDesignateG0123CharacterSet96;
- FDesignatingCharacterSet := gcsG2;
- end;
- '/':
- begin
- FState := tsmsDesignateG0123CharacterSet96;
- FDesignatingCharacterSet := gcsG3;
- end;
- '7':
- begin
- SaveCursor;
- FState := tsmsInitial;
- end;
- '8':
- begin
- RestoreCursor;
- FState := tsmsInitial;
- end;
- 'c':
- HardReset;
- 'n':
- FGLCharacterSet := gcsG2;
- 'o':
- FGLCharacterSet := gcsG3;
- '|':
- FGRCharacterSet := gcsG3;
- '}':
- FGRCharacterSet := gcsG2;
- '~':
- FGRCharacterSet := gcsG1;
- else
- begin
- { error }
- FLogger.LogMessage(vlWarning, 'Unhandled ESC sequence character: #' + IntToStr(Ord(Ch)));
- FState := tsmsInitial;
- end;
- end;
- end;
- tsmsDesignateG0123CharacterSet94:
- begin
- case Ch of
- 'A':
- begin
- FGCharacterSets[FDesignatingCharacterSet] := dcsBritishNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'B':
- begin
- FGCharacterSets[FDesignatingCharacterSet] := dcsUSASCII;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'C', '5':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsFinnishNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'H', '7':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsSwedishNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'K':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsGermanNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'Q', '9':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsFrenchCanadianNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'R', 'f':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsFrenchNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'Y':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsItalianNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'Z':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsSpanishNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '4':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsDutchNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '=':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsSwissNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '`', 'E', '6':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsNorwegianDanishNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '0':
- begin
- FGCharacterSets[FDesignatingCharacterSet] := dcsDecSpecialGraphics;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '<':
- begin
- if FDecConformanceLevel >= dclVT200 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsDecSupplemental;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '>':
- begin
- if FDecConformanceLevel >= dclVT300 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsDecTechnical;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '%':
- FState := tsmsDesignateG0123CharacterSet94_Percent;
- '"':
- FState := tsmsDesignateG0123CharacterSet94_Quote;
- '&':
- FState := tsmsDesignateG0123CharacterSet94_Ampersand;
- #27:
- begin
- FState := tsmsESC;
- FDesignatingCharacterSet := gcsG0;
- end;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' Character Set not implemented: ' + Ch);
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- end;
- end;
- tsmsDesignateG0123CharacterSet94_Percent:
- begin
- case Ch of
- '0':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsDecTurkish;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '2':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsTurkishNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '5':
- begin
- if FDecConformanceLevel >= dclVT300 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsDecSupplemental;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '6':
- begin
- if FDecConformanceLevel >= dclVT300 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsPortugueseNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '=':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsHebrewNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- #27:
- begin
- FState := tsmsESC;
- FDesignatingCharacterSet := gcsG0;
- end;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' Character Set not implemented: %' + Ch);
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- end;
- end;
- tsmsDesignateG0123CharacterSet94_Quote:
- begin
- case Ch of
- '>':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsGreekNRCS;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '4':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsDecHebrew;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- '?':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsDecGreek;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- #27:
- begin
- FState := tsmsESC;
- FDesignatingCharacterSet := gcsG0;
- end;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' Character Set not implemented: "' + Ch);
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- end;
- end;
- tsmsDesignateG0123CharacterSet94_Ampersand:
- begin
- case Ch of
- '4':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsDecCyrillic;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- #27:
- begin
- FState := tsmsESC;
- FDesignatingCharacterSet := gcsG0;
- end;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' Character Set not implemented: &' + Ch);
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- end;
- end;
- tsmsDesignateG0123CharacterSet96:
- begin
- case Ch of
- 'A':
- begin
- if FDecConformanceLevel >= dclVT300 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsISOLatin1Supplemental;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'B':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsISOLatin2Supplemental;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'F':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsISOGreekSupplemental;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'H':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsISOHebrewSupplemental;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'L':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsISOLatinCyrillic;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- 'M':
- begin
- if FDecConformanceLevel >= dclVT500 then
- FGCharacterSets[FDesignatingCharacterSet] := dcsISOLatin5Supplemental;
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- #27:
- begin
- FState := tsmsESC;
- FDesignatingCharacterSet := gcsG0;
- end;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' 96-Character Set not implemented: ' + Ch);
- FState := tsmsInitial;
- FDesignatingCharacterSet := gcsG0;
- end;
- end;
- end;
- tsmsESC_SP:
- begin
- case Ch of
- 'F':
- begin
- if FDecConformanceLevel >= dclVT200 then
- Exclude(FModeFlags, tmfSend8BitC1Controls);
- FState := tsmsInitial;
- end;
- 'G':
- begin
- if FDecConformanceLevel >= dclVT200 then
- Include(FModeFlags, tmfSend8BitC1Controls);
- FState := tsmsInitial;
- end;
- #27:
- FState := tsmsESC;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Unhandled ESC SP sequence character: #' + IntToStr(Ord(Ch)));
- FState := tsmsInitial;
- end;
- end;
- end;
- tsmsESC_Hash:
- begin
- case Ch of
- { DEC Screen Alignment Test (DECALN), VT100 }
- '8':
- begin
- for Y := 0 to FModel.Height - 1 do
- for X := 0 to FModel.Width - 1 do
- FModel.Cell[Y, X] := Cell('E', DefaultAttribute);
- FScrollingRegionTop := 0;
- FScrollingRegionBottom := FModel.Height - 1;
- FModel.SetCursorPos(CursorHomeX, CursorHomeY);
- FState := tsmsInitial;
- end;
- #27:
- FState := tsmsESC;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Unhandled ESC # sequence character: #' + IntToStr(Ord(Ch)));
- FState := tsmsInitial;
- end;
- end;
- end;
- tsmsESC_Percent:
- begin
- case Ch of
- '@':
- begin
- Exclude(FModeFlags, tmfUTF8Mode);
- FState := tsmsInitial;
- end;
- 'G':
- begin
- Include(FModeFlags, tmfUTF8Mode);
- FState := tsmsInitial;
- end;
- #27:
- FState := tsmsESC;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Unhandled ESC % sequence character: #' + IntToStr(Ord(Ch)));
- FState := tsmsInitial;
- end;
- end;
- end;
- tsmsCSI:
- begin
- case Ch of
- C0_CR:
- HandleCR;
- C0_VT,
- C0_FF,
- C0_LF:
- HandleLF;
- C0_BS:
- HandleBS;
- { Parameter Byte }
- { 0123456789:;<=>? }
- #$30..#$3F:
- begin
- if FControlSequenceIntermediate <> '' then
- begin
- { error }
- FLogger.LogMessage(vlWarning, 'Invalid CSI control sequence parameter byte following after intermediate bytes: ' + FControlSequenceParameter + FControlSequenceIntermediate + Ch);
- FState := tsmsInitial;
- ClearControlSequence;
- end
- else
- FControlSequenceParameter := FControlSequenceParameter + Ch;
- end;
- { Intermediate Byte }
- { !"#$%&'()*+,-./ }
- #$20..#$2F:
- begin
- FControlSequenceIntermediate := FControlSequenceIntermediate + Ch;
- end;
- { Final Byte }
- //@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
- #$40..#$7E:
- begin
- FControlSequenceFinalByte := Ch;
- ExecuteControlSequence;
- if FDecConformanceLevel = dclVT52 then
- FState := tsmsVT52_Initial
- else
- FState := tsmsInitial;
- ClearControlSequence;
- end;
- else
- begin
- { error }
- FLogger.LogMessage(vlWarning, 'Unhandled CSI control sequence character: ' + FControlSequenceParameter + FControlSequenceIntermediate + Ch);
- FState := tsmsInitial;
- ClearControlSequence;
- end;
- end;
- end;
- tsmsOSC:
- begin
- case Ch of
- #8..#13,#$20..#$7E:
- FOperatingSystemCommand := FOperatingSystemCommand + Ch;
- C1_ST:
- begin
- ExecuteOSC;
- FOperatingSystemCommand := '';
- FState := tsmsInitial;
- end;
- C0_ESC:
- FState := tsmsOSC_ESC;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Invalid OSC control sequence character: ' + FOperatingSystemCommand + Ch);
- FOperatingSystemCommand := '';
- FState := tsmsInitial;
- end;
- end;
- end;
- tsmsOSC_ESC:
- begin
- case Ch of
- Chr(Ord(C1_ST) - $40):
- begin
- ExecuteOSC;
- FOperatingSystemCommand := '';
- FState := tsmsInitial;
- end;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Invalid OSC control sequence character: ' + FOperatingSystemCommand + #27 + Ch);
- FOperatingSystemCommand := '';
- FState := tsmsInitial;
- end;
- end;
- end;
- tsmsDCS:
- begin
- case Ch of
- #8..#13,#$20..#$7E:
- FDeviceControlString := FDeviceControlString + Ch;
- C1_ST:
- begin
- ExecuteDCS;
- FDeviceControlString := '';
- FState := tsmsInitial;
- end;
- C0_ESC:
- FState := tsmsDCS_ESC;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Invalid DCS control sequence character: ' + FDeviceControlString + Ch);
- FDeviceControlString := '';
- FState := tsmsInitial;
- end;
- end;
- end;
- tsmsDCS_ESC:
- begin
- case Ch of
- Chr(Ord(C1_ST) - $40):
- begin
- ExecuteDCS;
- FDeviceControlString := '';
- FState := tsmsInitial;
- end;
- else
- begin
- FLogger.LogMessage(vlWarning, 'Invalid DCS control sequence character: ' + FDeviceControlString + #27 + Ch);
- FDeviceControlString := '';
- FState := tsmsInitial;
- end;
- end;
- end;
- tsmsUTF8_1ByteLeft:
- begin
- case Ch of
- #%10000000..#%10111111:
- begin
- FUTF8_Build := (FUTF8_Build shl 6) or (Ord(Ch) and %111111);
- WriteUTF32Char(FUTF8_Build);
- FState := tsmsInitial;
- end;
- else
- begin
- { error }
- FLogger.LogMessage(vlWarning, 'Invalid UTF-8 continuation byte: #' + IntToStr(Ord(Ch)));
- FState := tsmsInitial;
- FUTF8_Build := 0;
- end;
- end;
- end;
- tsmsUTF8_2BytesLeft:
- begin
- case Ch of
- #%10000000..#%10111111:
- begin
- FUTF8_Build := (FUTF8_Build shl 6) or (Ord(Ch) and %111111);
- FState := tsmsUTF8_1ByteLeft;
- end;
- else
- begin
- { error }
- FLogger.LogMessage(vlWarning, 'Invalid UTF-8 continuation byte: #' + IntToStr(Ord(Ch)));
- FState := tsmsInitial;
- FUTF8_Build := 0;
- end;
- end;
- end;
- tsmsUTF8_3BytesLeft:
- begin
- case Ch of
- #%10000000..#%10111111:
- begin
- FUTF8_Build := (FUTF8_Build shl 6) or (Ord(Ch) and %111111);
- FState := tsmsUTF8_2BytesLeft;
- end;
- else
- begin
- { error }
- FLogger.LogMessage(vlWarning, 'Invalid UTF-8 continuation byte: #' + IntToStr(Ord(Ch)));
- FState := tsmsInitial;
- FUTF8_Build := 0;
- end;
- end;
- end;
- tsmsVT52_Initial:
- begin
- case Chr(Ord(Ch) and 127) of
- C0_CR:
- HandleCR;
- C0_LF:
- HandleLF;
- C0_BS:
- HandleBS;
- C0_HT:
- HandleHT;
- C0_ESC:
- FState := tsmsVT52_ESC;
- #32..#126:
- WriteVT52Char(Ch);
- else
- FLogger.LogMessage(vlWarning, 'Unhandled character (VT52 mode): #' + IntToStr(Ord(Ch)));
- end;
- end;
- tsmsVT52_ESC:
- begin
- case Chr(Ord(Ch) and 127) of
- { Exit VT52 mode (Enter VT100 mode). }
- '<':
- if TerminalType >= ttVT100 then
- LeaveVT52Mode;
- { Cursor up. }
- 'A':
- begin
- FModel.SetCursorPos(FModel.CursorX, Max(FModel.CursorY - 1, 0));
- FNextCharacterWrapsToNextLine := False;
- FState := tsmsVT52_Initial;
- end;
- { Cursor down. }
- 'B':
- begin
- FModel.SetCursorPos(FModel.CursorX, Min(FModel.CursorY + 1, FModel.Height - 1));
- FNextCharacterWrapsToNextLine := False;
- FState := tsmsVT52_Initial;
- end;
- { Cursor right. }
- 'C':
- begin
- FModel.SetCursorPos(Min(FModel.CursorX + 1, FModel.Width - 1), FModel.CursorY);
- FNextCharacterWrapsToNextLine := False;
- FState := tsmsVT52_Initial;
- end;
- { Cursor left. }
- 'D':
- begin
- FModel.SetCursorPos(Max(FModel.CursorX - 1, 0), FModel.CursorY);
- FNextCharacterWrapsToNextLine := False;
- FState := tsmsVT52_Initial;
- end;
- { Enter graphics mode. }
- 'F':
- begin
- FVT52CharacterSet := v52csGraphics;
- FState := tsmsVT52_Initial;
- end;
- { Exit graphics mode. }
- 'G':
- begin
- FVT52CharacterSet := v52csAscii;
- FState := tsmsVT52_Initial;
- end;
- { Move the cursor to the home position. }
- 'H':
- begin
- FModel.SetCursorPos(0, 0);
- FNextCharacterWrapsToNextLine := False;
- FState := tsmsVT52_Initial;
- end;
- { Reverse line feed. }
- 'I':
- begin
- HandleC1(C1_RI);
- FState := tsmsVT52_Initial;
- end;
- { Erase from the cursor to the end of the screen. }
- 'J':
- begin
- ErasePageToBottom;
- FState := tsmsVT52_Initial;
- end;
- { Erase from the cursor to the end of the line. }
- 'K':
- begin
- EraseLineToRight;
- FState := tsmsVT52_Initial;
- end;
- 'Y':
- FState := tsmsVT52_ESC_Y;
- { Identify. }
- 'Z':
- begin
- { "I am a VT52." }
- TransmitStr(#27'/Z');
- end;
- else
- begin
- { error }
- FLogger.LogMessage(vlWarning, 'Unhandled ESC sequence character (VT52 mode): #' + IntToStr(Ord(Ch)));
- FState := tsmsVT52_Initial;
- end;
- end;
- end;
- tsmsVT52_ESC_Y:
- begin
- case Chr(Ord(Ch) and 127) of
- #32..#127:
- begin
- FModel.SetCursorPos(FModel.CursorX, EnsureRange((Ord(Ch) and 127) - 32, 0, FModel.Height - 1));
- FState := tsmsVT52_ESC_Y_Ps;
- end;
- else
- FLogger.LogMessage(vlWarning, 'Unhandled ESC Y sequence character (VT52 mode): #' + IntToStr(Ord(Ch)));
- end;
- end;
- tsmsVT52_ESC_Y_Ps:
- begin
- case Chr(Ord(Ch) and 127) of
- #32..#127:
- begin
- FModel.SetCursorPos(EnsureRange((Ord(Ch) and 127) - 32, 0, FModel.Width - 1), FModel.CursorY);
- FState := tsmsVT52_Initial;
- end;
- else
- FLogger.LogMessage(vlWarning, 'Unhandled ESC Y Ps sequence character (VT52 mode): #' + IntToStr(Ord(Ch)));
- end;
- end;
- end;
- end;
- FModel.UpdateScreen;
- end;
- procedure TTerminalController.MaybeLocalEcho(const ks: rawbytestring);
- begin
- if not (tmfSendReceiveMode in FModeFlags) then
- begin
- { todo: handle non-ASCII characters }
- if (Length(ks) = 1) and ((Ord(ks[1]) >= 32) and (Ord(ks[1]) <= 126)) then
- ReceiveData(ks[1], 1);
- end;
- end;
- procedure TTerminalController.HandleMouseEvent(const pdev: TPointingDeviceEvent);
- procedure SendX10MouseEvent(X, Y, Button: Integer; Press: Boolean);
- var
- PressChar: Char;
- begin
- if (X < 0) or (Y < 0) or (Button < 0) then
- exit;
- if Press then
- PressChar := 'M'
- else
- PressChar := 'm';
- case FMouseProtocolEncoding of
- tmpeX10:
- begin
- if ((32 + X) > 255) or ((32 + Y) > 255) or ((32 + Button) > 255) then
- exit;
- TransmitStr(EncodeReturnC1(C1_CSI) + PressChar + Chr(32 + Button) + Chr(32 + X) + Chr(32 + Y));
- end;
- tmpeUTF8:
- begin
- if (X > 2015) or (Y > 2015) or (Button > 2015) then
- exit;
- TransmitStr(EncodeReturnC1(C1_CSI) + PressChar + UTF8Encode(WideChar(32 + Button)) + UTF8Encode(WideChar(32 + X)) + UTF8Encode(WideChar(32 + Y)));
- end;
- tmpeSGR:
- TransmitStr(EncodeReturnC1(C1_CSI) + '<' + IntToStr(Button) + ';' + IntToStr(X) + ';' + IntToStr(Y) + PressChar);
- end;
- end;
- var
- MouseX, MouseY: Integer;
- MouseMoved: Boolean;
- ButtonsPressed, ButtonsReleased: TPointingDeviceButtonState;
- procedure SendNormalEvent;
- const
- ButtonTranslation: array [pdButton1..pdButton11] of Integer = (0, 2, 1, 64, 65, 66, 67, 128, 129, 130, 131);
- var
- Mask: Byte = 0;
- B: TPointingDeviceButton;
- begin
- for B := Low(ButtonTranslation) to High(ButtonTranslation) do
- if B in ButtonsPressed then
- SendX10MouseEvent(MouseX + 1, MouseY + 1, ButtonTranslation[B] or Mask, True);
- for B := Low(ButtonTranslation) to High(ButtonTranslation) do
- if B in ButtonsReleased then
- SendX10MouseEvent(MouseX + 1, MouseY + 1, ButtonTranslation[B] or Mask, False);
- if (ButtonsPressed = []) and (ButtonsReleased = []) then
- begin
- if not MouseMoved then
- exit;
- if pdev.ButtonState = [] then
- SendX10MouseEvent(MouseX + 1, MouseY + 1, (32 + 3) or Mask, True)
- else
- for B := Low(ButtonTranslation) to High(ButtonTranslation) do
- if B in pdev.ButtonState then
- begin
- SendX10MouseEvent(MouseX + 1, MouseY + 1, ButtonTranslation[B] or 32 or Mask, True);
- break;
- end;
- end;
- end;
- begin
- MouseX := pdev.X;
- MouseY := pdev.Y;
- MouseMoved := (MouseX <> FOldMouseX) or (MouseY <> FOldMouseY);
- ButtonsPressed := pdev.ButtonState - FOldMouseButtons;
- ButtonsReleased := FOldMouseButtons - pdev.ButtonState;
- case FMouseTrackingMode of
- tmtmX10:
- if ButtonsPressed <> [] then
- begin
- if pdButton1 in ButtonsPressed then
- SendX10MouseEvent(MouseX + 1, MouseY + 1, 0, True);
- if pdButton2 in ButtonsPressed then
- SendX10MouseEvent(MouseX + 1, MouseY + 1, 2, True);
- if pdButton3 in ButtonsPressed then
- SendX10MouseEvent(MouseX + 1, MouseY + 1, 1, True);
- end;
- tmtmNormal:
- if (ButtonsPressed <> []) or (ButtonsReleased <> []) then
- SendNormalEvent;
- tmtmButtonEvent:
- if (ButtonsPressed <> []) or (ButtonsReleased <> []) or (pdev.ButtonState <> []) then
- SendNormalEvent;
- tmtmAnyEvent:
- SendNormalEvent;
- end;
- FOldMouseX := MouseX;
- FOldMouseY := MouseY;
- FOldMouseButtons := pdev.ButtonState;
- end;
- function TTerminalController.EncodeReturnC1(Ch: TC1Char): string;
- begin
- if tmfSend8BitC1Controls in FModeFlags then
- Result := Ch
- else
- Result := #27 + Chr(Ord(Ch) - $40);
- end;
- end.
|