fpterm.controller.pas 120 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801
  1. { This file is part of fpterm - a terminal emulator, written in Free Pascal
  2. Copyright (C) 2022, 2024 Nikolay Nikolov <[email protected]>
  3. This library is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU Library General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or (at your
  6. option) any later version with the following modification:
  7. As a special exception, the copyright holders of this library give you
  8. permission to link this library with independent modules to produce an
  9. executable, regardless of the license terms of these independent modules,and
  10. to copy and distribute the resulting executable under terms of your choice,
  11. provided that you also meet, for each linked independent module, the terms
  12. and conditions of the license of that module. An independent module is a
  13. module which is not derived from or based on this library. If you modify
  14. this library, you may extend this exception to your version of the library,
  15. but you are not obligated to do so. If you do not wish to do so, delete this
  16. exception statement from your version.
  17. This program is distributed in the hope that it will be useful, but WITHOUT
  18. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  19. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  20. for more details.
  21. You should have received a copy of the GNU Library General Public License
  22. along with this library; if not, write to the Free Software Foundation,
  23. Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.
  24. }
  25. unit FpTerm.Controller;
  26. {$mode objfpc}{$H+}
  27. interface
  28. uses
  29. FpTerm.Base, FpTerm.Model, FpTerm.Logger;
  30. type
  31. TTerminalStateMachineState = (
  32. tsmsInitial,
  33. tsmsESC,
  34. tsmsESC_SP,
  35. tsmsESC_Hash, { ESC # }
  36. tsmsESC_Percent,
  37. tsmsCSI,
  38. tsmsOSC,
  39. tsmsOSC_ESC,
  40. tsmsDCS,
  41. tsmsDCS_ESC,
  42. tsmsDesignateG0123CharacterSet94,
  43. tsmsDesignateG0123CharacterSet94_Percent,
  44. tsmsDesignateG0123CharacterSet94_Quote,
  45. tsmsDesignateG0123CharacterSet94_Ampersand,
  46. tsmsDesignateG0123CharacterSet96,
  47. tsmsUTF8_1ByteLeft,
  48. tsmsUTF8_2BytesLeft,
  49. tsmsUTF8_3BytesLeft,
  50. tsmsVT52_Initial,
  51. tsmsVT52_ESC,
  52. tsmsVT52_ESC_Y,
  53. tsmsVT52_ESC_Y_Ps
  54. );
  55. TTerminalModeFlag = (
  56. tmfCursorKeysSendApplicationSequences,
  57. tmfAutoNewLine,
  58. tmfAutoWrapMode,
  59. tmfBracketedPasteMode,
  60. tmfSend8BitC1Controls,
  61. tmfAllow80To132ModeSwitching,
  62. tmfInsertMode,
  63. tmfOriginMode,
  64. tmfSendReceiveMode,
  65. tmfKeyboardActionMode,
  66. tmfReverseVideo,
  67. tmfUTF8Mode
  68. );
  69. TTerminalModeFlags = set of TTerminalModeFlag;
  70. TTerminalMouseTrackingMode = (
  71. tmtmNone,
  72. tmtmX10,
  73. tmtmNormal,
  74. tmtmHighlight,
  75. tmtmButtonEvent,
  76. tmtmAnyEvent
  77. );
  78. TTerminalMouseProtocolEncoding = (
  79. tmpeX10,
  80. tmpeUTF8,
  81. tmpeSGR,
  82. tmpeURXVT,
  83. tmpeSGRPixels
  84. );
  85. TTerminalType = (
  86. ttVT52,
  87. ttVT100,
  88. ttVT101,
  89. ttVT102,
  90. ttVT125,
  91. ttVT131,
  92. ttVT132,
  93. ttVT220,
  94. ttVT240,
  95. ttVT241,
  96. ttVT320,
  97. ttVT330,
  98. ttVT340,
  99. ttVT382,
  100. ttVT420,
  101. ttVT510,
  102. ttVT520,
  103. ttVT525
  104. );
  105. TDecConformanceLevel = (
  106. dclVT52,
  107. dclVT100, { VT100/VT101/VT102/VT105/VT125/VT131/VT180 }
  108. dclVT200, { VT220/VT240/VT241 }
  109. dclVT300, { VT320/VT340 }
  110. dclVT400, { VT420 }
  111. dclVT500 { VT510/VT520/VT525 }
  112. );
  113. TGCharacterSet = (
  114. gcsG0,
  115. gcsG1,
  116. gcsG2,
  117. gcsG3
  118. );
  119. TDecCharacterSet = (
  120. dcsUSASCII, { VT100 }
  121. dcsBritishNRCS, { VT100 }
  122. dcsFinnishNRCS, { VT200 }
  123. dcsSwedishNRCS, { VT200 }
  124. dcsGermanNRCS, { VT200 }
  125. dcsFrenchCanadianNRCS, { VT200 }
  126. dcsFrenchNRCS, { VT200 }
  127. dcsItalianNRCS, { VT200 }
  128. dcsSpanishNRCS, { VT200 }
  129. dcsDutchNRCS, { VT200 }
  130. dcsGreekNRCS, { VT500 }
  131. dcsTurkishNRCS, { VT500 }
  132. dcsPortugueseNRCS, { VT300 }
  133. dcsHebrewNRCS, { VT500 }
  134. dcsSwissNRCS, { VT200 }
  135. dcsNorwegianDanishNRCS, { VT200 }
  136. dcsDecSpecialGraphics, { VT100 }
  137. dcsDecSupplemental, { VT200 }
  138. dcsDecTechnical, { VT300 }
  139. dcsDecHebrew, { VT500 }
  140. dcsDecGreek, { VT500 }
  141. dcsDecTurkish, { VT500 }
  142. dcsDecCyrillic, { VT500 }
  143. dcsScsNRCS, { VT500 }
  144. dcsRussianNRCS, { VT500 }
  145. { 96-character sets }
  146. dcsISOLatin1Supplemental, { VT300 }
  147. dcsISOLatin2Supplemental, { VT500 }
  148. dcsISOGreekSupplemental, { VT500 }
  149. dcsISOHebrewSupplemental, { VT500 }
  150. dcsISOLatinCyrillic, { VT500 }
  151. dcsISOLatin5Supplemental { VT500 }
  152. );
  153. const
  154. CharacterSets96 = [dcsISOLatin1Supplemental..dcsISOLatin5Supplemental];
  155. type
  156. TVT52CharacterSet = (
  157. v52csASCII,
  158. v52csGraphics
  159. );
  160. const
  161. DefaultModeFlags: TTerminalModeFlags = [tmfAutoWrapMode, tmfSendReceiveMode, tmfUTF8Mode];
  162. MaxWidth = 65536;
  163. type
  164. TTransmitDataEvent = procedure(const buf; Bytes: SizeUInt) of object;
  165. TResizeEvent = procedure(NewWidth, NewHeight: Integer) of object;
  166. TTerminalSavedCursorFlag = (
  167. tscfOriginMode,
  168. tscfNextCharacterWrapsToNextLine
  169. );
  170. TTerminalSavedCursorFlags = set of TTerminalSavedCursorFlag;
  171. const
  172. DefaultSavedCursorFlags: TTerminalSavedCursorFlags = [];
  173. type
  174. { TTerminalSavedCursor }
  175. TTerminalSavedCursor = class
  176. private
  177. FCursorX: Integer;
  178. FCursorY: Integer;
  179. FCursorVisible: Boolean;
  180. FAttribute: TAttribute;
  181. FGLCharacterSet: TGCharacterSet;
  182. FGRCharacterSet: TGCharacterSet;
  183. FGCharacterSets: array [TGCharacterSet] of TDecCharacterSet;
  184. FFlags: TTerminalSavedCursorFlags;
  185. function GetCharacterSets(Index: TGCharacterSet): TDecCharacterSet;
  186. procedure SetCharacterSets(Index: TGCharacterSet; AValue: TDecCharacterSet);
  187. public
  188. constructor Create;
  189. procedure Reset;
  190. property CursorX: Integer read FCursorX write FCursorX;
  191. property CursorY: Integer read FCursorY write FCursorY;
  192. property CursorVisible: Boolean read FCursorVisible write FCursorVisible;
  193. property Attribute: TAttribute read FAttribute write FAttribute;
  194. property GLCharacterSet: TGCharacterSet read FGLCharacterSet write FGLCharacterSet;
  195. property GRCharacterSet: TGCharacterSet read FGRCharacterSet write FGRCharacterSet;
  196. property GCharacterSets[Index: TGCharacterSet]: TDecCharacterSet read GetCharacterSets write SetCharacterSets;
  197. property Flags: TTerminalSavedCursorFlags read FFlags write FFlags;
  198. end;
  199. { TTerminalTabStops }
  200. TTerminalTabStops = class
  201. private
  202. FTabStops: bitpacked array [0..MaxWidth - 1] of Boolean;
  203. function GetTabStop(Index: Integer): Boolean;
  204. procedure SetTabStop(Index: Integer; AValue: Boolean);
  205. public
  206. constructor Create;
  207. procedure Clear;
  208. procedure Reset;
  209. property TabStop[Index: Integer]: Boolean read GetTabStop write SetTabStop; default;
  210. end;
  211. { TTerminalController }
  212. TTerminalController = class
  213. private
  214. function GetCursorHomeX: Integer;
  215. function GetCursorHomeY: Integer;
  216. function GetCursorLimitX: Integer;
  217. function GetCursorLimitY: Integer;
  218. function GetCursorMinX: Integer;
  219. function GetCursorMinY: Integer;
  220. function GetCursorOriginX: Integer;
  221. function GetCursorOriginY: Integer;
  222. private
  223. FTerminalType: TTerminalType;
  224. FState: TTerminalStateMachineState;
  225. FUTF8_Build: LongWord;
  226. FLastGraphicCharacter: TExtendedGraphemeCluster;
  227. FNextCharacterWrapsToNextLine: Boolean;
  228. FSavedCursor: TTerminalSavedCursor;
  229. FAttribute: TAttribute;
  230. FModeFlags: TTerminalModeFlags;
  231. FDecConformanceLevel: TDecConformanceLevel;
  232. FDesignatingCharacterSet: TGCharacterSet;
  233. FGLCharacterSet: TGCharacterSet;
  234. FGRCharacterSet: TGCharacterSet;
  235. FGCharacterSets: array [TGCharacterSet] of TDecCharacterSet;
  236. FVT52CharacterSet: TVT52CharacterSet;
  237. FScrollingRegionTop: Integer;
  238. FScrollingRegionBottom: Integer;
  239. FScrollingRegionLeft: Integer;
  240. FScrollingRegionRight: Integer;
  241. {CSI control sequence}
  242. FControlSequenceParameter: string;
  243. FControlSequenceIntermediate: string;
  244. FControlSequenceFinalByte: Char;
  245. {OSC}
  246. FOperatingSystemCommand: string;
  247. {DCS}
  248. FDeviceControlString: string;
  249. FMouseTrackingMode: TTerminalMouseTrackingMode;
  250. FMouseProtocolEncoding: TTerminalMouseProtocolEncoding;
  251. FOldMouseX, FOldMouseY: Integer;
  252. FOldMouseButtons: TPointingDeviceButtonState;
  253. FTabStops: TTerminalTabStops;
  254. FModel: TTerminalModel;
  255. FOnTransmitData: TTransmitDataEvent;
  256. FOnResize: TResizeEvent;
  257. FLogger: TLogger;
  258. FVT100AnswerbackString: string;
  259. function ParseControlSequenceParams_Int(const CommandName: string; var i1: Integer): Boolean;
  260. function ParseControlSequenceParams_Int_Int(const CommandName: string; var i1, i2: Integer): Boolean;
  261. procedure SaveCursor;
  262. procedure RestoreCursor;
  263. procedure ClearControlSequence;
  264. procedure ExecuteControlSequence;
  265. procedure ExecuteOSC;
  266. procedure ExecuteDCS;
  267. procedure ExecuteDECRQSS(const ReqStr: string);
  268. procedure HandleSGRAttribute(SGRAttr: string);
  269. procedure ScrollUp(LinesCount: Integer = 1);
  270. procedure ScrollDown(LinesCount: Integer = 1);
  271. procedure ScrollLeft(CharCount: Integer);
  272. procedure ScrollRight(CharCount: Integer);
  273. procedure InsertLines(LinesCount: Integer);
  274. procedure DeleteLines(LinesCount: Integer);
  275. procedure DeleteCharacters(CharCount: Integer);
  276. procedure ErasePage;
  277. procedure ErasePageToBottom;
  278. procedure ErasePageToTop;
  279. procedure EraseLineToRight;
  280. procedure EraseLineToLeft;
  281. procedure EraseLine;
  282. procedure EraseCharacters(CharCount: Integer);
  283. procedure InsertBlankCharacters(CharCount: Integer);
  284. procedure WriteUTF32Char(const UTF32Char: LongWord);
  285. procedure WriteVT100CharFromCharset(Ch: Char; Charset: TDecCharacterSet);
  286. procedure WriteVT100Char(Ch: Char);
  287. procedure WriteVT52Char(Ch: Char);
  288. procedure WriteRepeatedCharacter(const EGC: TExtendedGraphemeCluster; Count: Integer);
  289. procedure HandleC1(Ch: TC1Char);
  290. procedure HandleENQ;
  291. procedure HandleCR;
  292. procedure HandleLF;
  293. procedure HandleBS;
  294. procedure HandleHT;
  295. procedure CursorForwardTabulation(TabStops: Integer);
  296. procedure CursorBackwardTabulation(TabStops: Integer);
  297. procedure EnterVT52Mode;
  298. procedure LeaveVT52Mode;
  299. procedure TransmitData(const buf; Bytes: SizeUInt);
  300. procedure TransmitStr(const S: string);
  301. procedure HardReset;
  302. procedure SoftReset;
  303. property CursorHomeX: Integer read GetCursorHomeX;
  304. property CursorHomeY: Integer read GetCursorHomeY;
  305. property CursorOriginX: Integer read GetCursorOriginX;
  306. property CursorOriginY: Integer read GetCursorOriginY;
  307. property CursorMinX: Integer read GetCursorMinX;
  308. property CursorMinY: Integer read GetCursorMinY;
  309. property CursorLimitX: Integer read GetCursorLimitX;
  310. property CursorLimitY: Integer read GetCursorLimitY;
  311. public
  312. constructor Create(AModel: TTerminalModel; ATerminalType: TTerminalType);
  313. destructor Destroy; override;
  314. function Resize(NewWidth, NewHeight: Integer): Boolean;
  315. procedure ReceiveData(const buf; Bytes: SizeUInt);
  316. procedure MaybeLocalEcho(const ks: rawbytestring);
  317. procedure HandleMouseEvent(const pdev: TPointingDeviceEvent);
  318. function EncodeReturnC1(Ch: TC1Char): string;
  319. property OnTransmitData: TTransmitDataEvent read FOnTransmitData write FOnTransmitData;
  320. property OnResize: TResizeEvent read FOnResize write FOnResize;
  321. property ModeFlags: TTerminalModeFlags read FModeFlags;
  322. property VT100AnswerbackString: string read FVT100AnswerbackString write FVT100AnswerbackString;
  323. property TerminalType: TTerminalType read FTerminalType;
  324. end;
  325. implementation
  326. uses
  327. {$IFDEF FPC_DOTTEDUNITS}
  328. System.SysUtils, System.Math;
  329. {$ELSE FPC_DOTTEDUNITS}
  330. SysUtils, Math;
  331. {$ENDIF FPC_DOTTEDUNITS}
  332. const
  333. MaxConformanceLevelForTerminal: array [TTerminalType] of TDecConformanceLevel = (
  334. dclVT52, { ttVT52 }
  335. dclVT100, { ttVT100 }
  336. dclVT100, { ttVT101 }
  337. dclVT100, { ttVT102 }
  338. dclVT100, { ttVT125 }
  339. dclVT100, { ttVT131 }
  340. dclVT100, { ttVT132 }
  341. dclVT200, { ttVT220 }
  342. dclVT200, { ttVT240 }
  343. dclVT200, { ttVT241 }
  344. dclVT300, { ttVT320 }
  345. dclVT300, { ttVT330 }
  346. dclVT300, { ttVT340 }
  347. dclVT300, { ttVT382 }
  348. dclVT400, { ttVT420 }
  349. dclVT500, { ttVT510 }
  350. dclVT500, { ttVT520 }
  351. dclVT500 { ttVT525 }
  352. );
  353. DecSpecialGraphicsCharacterSet: array [#$5F..#$7E] of UCS4Char = (
  354. $0020,
  355. $25C6, $2592, $2409, $240C, $240D, $240A, $00B0, $00B1, $2424, $240B, $2518, $2510, $250C, $2514, $253C, $23BA,
  356. $23BB, $2500, $23BC, $23BD, $251C, $2524, $2534, $252C, $2502, $2264, $2265, $03A0, $2260, $00A3, $00B7
  357. );
  358. DecTechnicalCharacterSet: array [#$21..#$7E] of UCS4Char = (
  359. $23B7, $250C, $2500, $2320, $2321, $2502, $23A1, $23A3, $23A4, $23A6, $23A7, $23A9, $23AB, $23AD, $23A8,
  360. $23AC, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $2264, $2260, $2265, $222B,
  361. $2234, $221D, $221E, $00F7, $0394, $2207, $03A6, $0393, $223C, $2243, $0398, $00D7, $039B, $21D4, $21D2, $2261,
  362. $03A0, $03A8, $FFFD, $03A3, $FFFD, $FFFD, $221A, $03A9, $039E, $03A5, $2282, $2283, $2229, $222A, $2227, $2228,
  363. $00AC, $03B1, $03B2, $03C7, $03B4, $03B5, $03C6, $03B3, $03B7, $03B9, $03B8, $03BA, $03BB, $FFFD, $03BD, $2202,
  364. $03C0, $03C8, $03C1, $03C3, $03C4, $FFFD, $0192, $03C9, $03BE, $03C5, $03B6, $2190, $2191, $2192, $2193
  365. );
  366. DecCyrillicCharacterSet: array [#$40..#$7E] of UCS4Char = (
  367. $044E, $0430, $0431, $0446, $0434, $0435, $0444, $0433, $0445, $0438, $0439, $043A, $043B, $043C, $043D, $043E,
  368. $043F, $044F, $0440, $0441, $0442, $0443, $0436, $0432, $044C, $044B, $0437, $0448, $044D, $0449, $0447, $044A,
  369. $042E, $0410, $0411, $0426, $0414, $0415, $0424, $0413, $0425, $0418, $0419, $041A, $041B, $041C, $041D, $041E,
  370. $041F, $042F, $0420, $0421, $0422, $0423, $0416, $0412, $042C, $042B, $0417, $0428, $042D, $0429, $0427
  371. );
  372. VT52GraphicsCharacterSet: array [#$5E..#$7E] of UCS4Char = (
  373. $0020, $0020,
  374. $0020, $2588, $215F, $00B3, $2075, $2077, $00B0, $00B1, $2192, $2026, $00F7, $2193, $2594,$1FB76,$1FB77,$1FB78,
  375. $1FB79,$1FB7A,$1FB7B, $2581, $2080, $2081, $2082, $2083, $2084, $2085, $2086, $2087, $2088, $2089, $00B6
  376. );
  377. function OnlyDigits(const S: string): Boolean;
  378. var
  379. Ch: Char;
  380. begin
  381. for Ch in S do
  382. if (Ch < '0') or (Ch > '9') then
  383. exit(False);
  384. Result := True;
  385. end;
  386. function ExtractStringParameter(var S: string): string;
  387. var
  388. I: SizeInt;
  389. begin
  390. I := Pos(';', S);
  391. if I = 0 then
  392. begin
  393. Result := S;
  394. S := '';
  395. end
  396. else
  397. begin
  398. Result := Copy(S, 1, I - 1);
  399. Delete(S, 1, I);
  400. end;
  401. end;
  402. function ExtractSGRParameter(var S: string): string;
  403. var
  404. P1, P2: LongInt;
  405. P2S, P3S, P4S, P5S: string;
  406. begin
  407. Result := ExtractStringParameter(S);
  408. if (Result <> '') and OnlyDigits(Result) then
  409. begin
  410. P1 := StrToInt(Result);
  411. if (P1 = 38) or (P1 = 48) then
  412. begin
  413. P2S := ExtractStringParameter(S);
  414. Result := Result + ':' + P2S;
  415. if (P2S <> '') and OnlyDigits(P2S) then
  416. begin
  417. P2 := StrToInt(P2S);
  418. case P2 of
  419. 5:
  420. begin
  421. P3S := ExtractStringParameter(S);
  422. if OnlyDigits(P3S) then
  423. Result := Result + ':' + P3S;
  424. end;
  425. 2:
  426. begin
  427. P3S := ExtractStringParameter(S);
  428. if OnlyDigits(P3S) then
  429. begin
  430. P4S := ExtractStringParameter(S);
  431. if OnlyDigits(P4S) then
  432. begin
  433. P5S := ExtractStringParameter(S);
  434. if OnlyDigits(P5S) then
  435. Result := Result + ':' + P3S + ':' + P4S + ':' + P5S;
  436. end
  437. else
  438. Result := Result + ':' + P3S + ':' + P4S;
  439. end
  440. else
  441. Result := Result + ':' + P3S;
  442. end;
  443. end;
  444. end;
  445. end;
  446. end;
  447. end;
  448. function ExtractIntParameter(var S: string; Default: Integer): Integer;
  449. var
  450. ParamS: string;
  451. begin
  452. ParamS := ExtractStringParameter(S);
  453. if ParamS = '' then
  454. Result := Default
  455. else
  456. Result := StrToInt(ParamS);
  457. end;
  458. { TTerminalSavedCursor }
  459. function TTerminalSavedCursor.GetCharacterSets(Index: TGCharacterSet): TDecCharacterSet;
  460. begin
  461. Result := FGCharacterSets[Index];
  462. end;
  463. procedure TTerminalSavedCursor.SetCharacterSets(Index: TGCharacterSet; AValue: TDecCharacterSet);
  464. begin
  465. FGCharacterSets[Index] := AValue;
  466. end;
  467. constructor TTerminalSavedCursor.Create;
  468. begin
  469. Reset;
  470. end;
  471. procedure TTerminalSavedCursor.Reset;
  472. begin
  473. FCursorX := 0;
  474. FCursorY := 0;
  475. FCursorVisible := True;
  476. FAttribute := DefaultAttribute;
  477. FGLCharacterSet := gcsG0;
  478. FGRCharacterSet := gcsG1;
  479. FGCharacterSets[gcsG0] := dcsUSASCII;
  480. FGCharacterSets[gcsG1] := dcsUSASCII;
  481. FGCharacterSets[gcsG2] := dcsUSASCII;
  482. FGCharacterSets[gcsG3] := dcsUSASCII;
  483. FFlags := DefaultSavedCursorFlags;
  484. end;
  485. { TTerminalTabStops }
  486. function TTerminalTabStops.GetTabStop(Index: Integer): Boolean;
  487. begin
  488. if (Index >= Low(FTabStops)) and (Index <= High(FTabStops)) then
  489. Result := FTabStops[Index]
  490. else
  491. Result := False;
  492. end;
  493. procedure TTerminalTabStops.SetTabStop(Index: Integer; AValue: Boolean);
  494. begin
  495. if (Index >= Low(FTabStops)) and (Index <= High(FTabStops)) then
  496. FTabStops[Index] := AValue;
  497. end;
  498. constructor TTerminalTabStops.Create;
  499. begin
  500. Reset;
  501. end;
  502. procedure TTerminalTabStops.Clear;
  503. begin
  504. FillChar(FTabStops, SizeOf(FTabStops), 0);
  505. end;
  506. procedure TTerminalTabStops.Reset;
  507. var
  508. I: Integer;
  509. begin
  510. Clear;
  511. for I := 0 to High(FTabStops) div 8 do
  512. TabStop[I * 8] := True;
  513. end;
  514. { TTerminalController }
  515. function TTerminalController.GetCursorHomeX: Integer;
  516. begin
  517. Result := 0;
  518. end;
  519. function TTerminalController.GetCursorHomeY: Integer;
  520. begin
  521. if tmfOriginMode in FModeFlags then
  522. Result := FScrollingRegionTop
  523. else
  524. Result := 0;
  525. end;
  526. function TTerminalController.GetCursorLimitX: Integer;
  527. begin
  528. Result := FModel.Width - 1;
  529. end;
  530. function TTerminalController.GetCursorLimitY: Integer;
  531. begin
  532. if tmfOriginMode in FModeFlags then
  533. Result := FScrollingRegionBottom
  534. else
  535. Result := FModel.Height - 1;
  536. end;
  537. function TTerminalController.GetCursorMinX: Integer;
  538. begin
  539. Result := 0;
  540. end;
  541. function TTerminalController.GetCursorMinY: Integer;
  542. begin
  543. Result := CursorHomeY;
  544. end;
  545. function TTerminalController.GetCursorOriginX: Integer;
  546. begin
  547. Result := 0;
  548. end;
  549. function TTerminalController.GetCursorOriginY: Integer;
  550. begin
  551. Result := CursorHomeY;
  552. end;
  553. function TTerminalController.ParseControlSequenceParams_Int(const CommandName: string; var i1: Integer): Boolean;
  554. var
  555. S: string;
  556. begin
  557. Result := False;
  558. if FControlSequenceIntermediate <> '' then
  559. begin
  560. FLogger.LogMessage(vlWarning, 'Unhandled ' + CommandName + ' intermediate bytes: ' + FControlSequenceIntermediate);
  561. exit;
  562. end;
  563. S := FControlSequenceParameter;
  564. try
  565. i1 := ExtractIntParameter(S, i1);
  566. except
  567. on e: EConvertError do
  568. begin
  569. FLogger.LogMessage(vlWarning, 'Invalid ' + CommandName + ' integer parameter: ' + FControlSequenceParameter);
  570. exit;
  571. end;
  572. end;
  573. if S <> '' then
  574. begin
  575. FLogger.LogMessage(vlWarning, 'Too many ' + CommandName + ' parameters: ' + FControlSequenceParameter);
  576. exit;
  577. end;
  578. Result := True;
  579. end;
  580. function TTerminalController.ParseControlSequenceParams_Int_Int(const CommandName: string; var i1, i2: Integer): Boolean;
  581. var
  582. S: string;
  583. begin
  584. Result := False;
  585. if FControlSequenceIntermediate <> '' then
  586. begin
  587. FLogger.LogMessage(vlWarning, 'Unhandled ' + CommandName + ' intermediate bytes: ' + FControlSequenceIntermediate);
  588. exit;
  589. end;
  590. S := FControlSequenceParameter;
  591. try
  592. i1 := ExtractIntParameter(S, i1);
  593. i2 := ExtractIntParameter(S, i2);
  594. except
  595. on e: EConvertError do
  596. begin
  597. FLogger.LogMessage(vlWarning, 'Invalid ' + CommandName + ' integer parameter: ' + FControlSequenceParameter);
  598. exit;
  599. end;
  600. end;
  601. if S <> '' then
  602. begin
  603. FLogger.LogMessage(vlWarning, 'Too many ' + CommandName + ' parameters: ' + FControlSequenceParameter);
  604. exit;
  605. end;
  606. Result := True;
  607. end;
  608. procedure TTerminalController.SaveCursor;
  609. var
  610. Flags: TTerminalSavedCursorFlags;
  611. begin
  612. { todo: shape, other attributes? }
  613. FSavedCursor.CursorX := FModel.CursorX;
  614. FSavedCursor.CursorY := FModel.CursorY;
  615. FSavedCursor.CursorVisible := FModel.CursorVisible;
  616. FSavedCursor.Attribute := FAttribute;
  617. FSavedCursor.GLCharacterSet := FGLCharacterSet;
  618. FSavedCursor.GRCharacterSet := FGRCharacterSet;
  619. FSavedCursor.GCharacterSets[gcsG0] := FGCharacterSets[gcsG0];
  620. FSavedCursor.GCharacterSets[gcsG1] := FGCharacterSets[gcsG1];
  621. FSavedCursor.GCharacterSets[gcsG2] := FGCharacterSets[gcsG2];
  622. FSavedCursor.GCharacterSets[gcsG3] := FGCharacterSets[gcsG3];
  623. Flags := [];
  624. if tmfOriginMode in ModeFlags then
  625. Include(Flags, tscfOriginMode);
  626. if FNextCharacterWrapsToNextLine then
  627. Include(Flags, tscfNextCharacterWrapsToNextLine);
  628. FSavedCursor.Flags := Flags;
  629. end;
  630. procedure TTerminalController.RestoreCursor;
  631. begin
  632. { todo: shape, other attributes? }
  633. FModel.SetCursorPos(EnsureRange(FSavedCursor.CursorX, CursorMinX, CursorLimitX), EnsureRange(FSavedCursor.FCursorY, CursorMinY, CursorLimitY));
  634. FNextCharacterWrapsToNextLine := tscfNextCharacterWrapsToNextLine in FSavedCursor.Flags;
  635. if FSavedCursor.CursorVisible then
  636. FModel.ShowCursor
  637. else
  638. FModel.HideCursor;
  639. FAttribute := FSavedCursor.Attribute;
  640. FGLCharacterSet := FSavedCursor.GLCharacterSet;
  641. FGRCharacterSet := FSavedCursor.GRCharacterSet;
  642. FGCharacterSets[gcsG0] := FSavedCursor.GCharacterSets[gcsG0];
  643. FGCharacterSets[gcsG1] := FSavedCursor.GCharacterSets[gcsG1];
  644. FGCharacterSets[gcsG2] := FSavedCursor.GCharacterSets[gcsG2];
  645. FGCharacterSets[gcsG3] := FSavedCursor.GCharacterSets[gcsG3];
  646. if tscfOriginMode in FSavedCursor.Flags then
  647. Include(FModeFlags, tmfOriginMode)
  648. else
  649. Exclude(FModeFlags, tmfOriginMode);
  650. end;
  651. procedure TTerminalController.ClearControlSequence;
  652. begin
  653. FControlSequenceParameter := '';
  654. FControlSequenceIntermediate := '';
  655. FControlSequenceFinalByte := #0;
  656. end;
  657. procedure TTerminalController.ExecuteControlSequence;
  658. procedure HandleSGR;
  659. var
  660. S, PS: string;
  661. I: SizeInt;
  662. begin
  663. if FControlSequenceIntermediate <> '' then
  664. FLogger.LogMessage(vlWarning, 'Unhandled SGR intermediate bytes: ' + FControlSequenceIntermediate);
  665. S := FControlSequenceParameter;
  666. if S = '' then
  667. S := '0';
  668. while S <> '' do
  669. begin
  670. PS := ExtractSGRParameter(S);
  671. HandleSGRAttribute(PS);
  672. end;
  673. end;
  674. var
  675. n, m: Integer;
  676. begin
  677. case FControlSequenceFinalByte of
  678. '@':
  679. begin
  680. if FControlSequenceIntermediate = ' ' then
  681. begin
  682. { SL - SCROLL LEFT }
  683. n := 1;
  684. FControlSequenceIntermediate := '';
  685. if ParseControlSequenceParams_Int('SL', n) then
  686. ScrollLeft(n);
  687. end
  688. else
  689. begin
  690. { ICH - INSERT CHARACTER }
  691. n := 1;
  692. if ParseControlSequenceParams_Int('ICH', n) then
  693. InsertBlankCharacters(n);
  694. end;
  695. end;
  696. { CUU - CURSOR UP }
  697. 'A':
  698. begin
  699. if FControlSequenceIntermediate = ' ' then
  700. begin
  701. { SR - SCROLL RIGHT }
  702. n := 1;
  703. FControlSequenceIntermediate := '';
  704. if ParseControlSequenceParams_Int('SR', n) then
  705. ScrollRight(n);
  706. end
  707. else
  708. begin
  709. n := 1;
  710. if ParseControlSequenceParams_Int('CUU', n) then
  711. begin
  712. FModel.SetCursorPos(FModel.CursorX, Max(FModel.CursorY - Max(n, 1), CursorMinY));
  713. FNextCharacterWrapsToNextLine := False;
  714. end;
  715. end;
  716. end;
  717. { CUD - CURSOR DOWN }
  718. 'B':
  719. begin
  720. n := 1;
  721. if ParseControlSequenceParams_Int('CUD', n) then
  722. begin
  723. FModel.SetCursorPos(FModel.CursorX, Min(FModel.CursorY + Max(n, 1), CursorLimitY));
  724. FNextCharacterWrapsToNextLine := False;
  725. end;
  726. end;
  727. { CUF - CURSOR RIGHT }
  728. 'C':
  729. begin
  730. n := 1;
  731. if ParseControlSequenceParams_Int('CUF', n) then
  732. begin
  733. FModel.SetCursorPos(Min(FModel.CursorX + Max(n, 1), CursorLimitX), FModel.CursorY);
  734. FNextCharacterWrapsToNextLine := False;
  735. end;
  736. end;
  737. { CUB - CURSOR LEFT }
  738. 'D':
  739. begin
  740. n := 1;
  741. if ParseControlSequenceParams_Int('CUB', n) then
  742. begin
  743. FModel.SetCursorPos(Max(FModel.CursorX - Max(n, 1), CursorMinX), FModel.CursorY);
  744. FNextCharacterWrapsToNextLine := False;
  745. end;
  746. end;
  747. { CNL - CURSOR NEXT LINE }
  748. 'E':
  749. begin
  750. n := 1;
  751. if ParseControlSequenceParams_Int('CNL', n) then
  752. begin
  753. FModel.SetCursorPos(0, Min(FModel.CursorY + Max(n, 1), CursorLimitY));
  754. FNextCharacterWrapsToNextLine := False;
  755. end;
  756. end;
  757. { CPL - CURSOR PRECEDING LINE }
  758. 'F':
  759. begin
  760. n := 1;
  761. if ParseControlSequenceParams_Int('CPL', n) then
  762. begin
  763. FModel.SetCursorPos(0, Max(FModel.CursorY - Max(n, 1), CursorMinY));
  764. FNextCharacterWrapsToNextLine := False;
  765. end;
  766. end;
  767. { CHA - CURSOR CHARACTER ABSOLUTE }
  768. 'G':
  769. begin
  770. n := 1;
  771. if ParseControlSequenceParams_Int('CHA', n) then
  772. begin
  773. FModel.SetCursorPos(EnsureRange(n - 1, CursorMinX, CursorLimitX), FModel.CursorY);
  774. FNextCharacterWrapsToNextLine := False;
  775. end;
  776. end;
  777. { CUP - CURSOR POSITION }
  778. 'H':
  779. begin
  780. n := 1;
  781. m := 1;
  782. if ParseControlSequenceParams_Int_Int('CUP', n, m) then
  783. begin
  784. FModel.SetCursorPos(EnsureRange(CursorOriginX + Max(m, 1) - 1, CursorMinX, CursorLimitX), EnsureRange(CursorOriginY + Max(n, 1) - 1, CursorMinY, CursorLimitY));
  785. FNextCharacterWrapsToNextLine := False;
  786. end;
  787. end;
  788. { CHT - CURSOR FORWARD TABULATION }
  789. 'I':
  790. begin
  791. n := 1;
  792. if ParseControlSequenceParams_Int('CHT', n) then
  793. CursorForwardTabulation(n);
  794. end;
  795. { ED - ERASE IN PAGE }
  796. 'J':
  797. begin
  798. n := 0;
  799. if ParseControlSequenceParams_Int('ED', n) then
  800. case n of
  801. 0:
  802. ErasePageToBottom;
  803. 1:
  804. ErasePageToTop;
  805. 2:
  806. ErasePage;
  807. else
  808. FLogger.LogMessage(vlWarning, 'Unsupported ED parameter: ' + FControlSequenceParameter);
  809. end;
  810. end;
  811. { EL - ERASE IN LINE }
  812. 'K':
  813. begin
  814. n := 0;
  815. if ParseControlSequenceParams_Int('EL', n) then
  816. case n of
  817. 0:
  818. EraseLineToRight;
  819. 1:
  820. EraseLineToLeft;
  821. 2:
  822. EraseLine;
  823. else
  824. FLogger.LogMessage(vlWarning, 'Unsupported EL parameter: ' + FControlSequenceParameter);
  825. end;
  826. end;
  827. { IL - INSERT LINE }
  828. 'L':
  829. begin
  830. n := 1;
  831. if ParseControlSequenceParams_Int('IL', n) then
  832. InsertLines(n);
  833. end;
  834. { DL - DELETE LINE }
  835. 'M':
  836. begin
  837. n := 1;
  838. if ParseControlSequenceParams_Int('DL', n) then
  839. DeleteLines(n);
  840. end;
  841. { DCH - DELETE CHARACTER }
  842. 'P':
  843. begin
  844. n := 1;
  845. if ParseControlSequenceParams_Int('DCH', n) then
  846. DeleteCharacters(n);
  847. end;
  848. { SU - SCROLL UP }
  849. 'S':
  850. begin
  851. n := 1;
  852. if ParseControlSequenceParams_Int('SU', n) then
  853. ScrollUp(n);
  854. end;
  855. { SD - SCROLL DOWN }
  856. 'T':
  857. begin
  858. n := 1;
  859. if ParseControlSequenceParams_Int('SD', n) then
  860. { unlike "CSI 0 S" and "CSI 0 ^", which scroll by one, "CSI 0 T" doesn't do anything in xterm }
  861. if n <> 0 then
  862. ScrollDown(n);
  863. end;
  864. { ECH - ERASE CHARACTER }
  865. 'X':
  866. begin
  867. n := 1;
  868. if ParseControlSequenceParams_Int('ECH', n) then
  869. EraseCharacters(n);
  870. end;
  871. { CBT - CURSOR BACKWARD TABULATION }
  872. 'Z':
  873. begin
  874. n := 1;
  875. if ParseControlSequenceParams_Int('CBT', n) then
  876. CursorBackwardTabulation(n);
  877. end;
  878. { SD - SCROLL DOWN - ECMA-48, publication error in the original ECMA-48 5th edition (1991), corrected in 2003 }
  879. '^':
  880. begin
  881. n := 1;
  882. if ParseControlSequenceParams_Int('SD', n) then
  883. ScrollDown(n);
  884. end;
  885. { HPA - CHARACTER POSITION ABSOLUTE }
  886. '`':
  887. begin
  888. n := 1;
  889. if ParseControlSequenceParams_Int('HPA', n) then
  890. begin
  891. FModel.SetCursorPos(EnsureRange(CursorOriginX + Max(n, 1) - 1, CursorMinX, CursorLimitX), FModel.CursorY);
  892. FNextCharacterWrapsToNextLine := False;
  893. end;
  894. end;
  895. { HPR - CHARACTER POSITION FORWARD }
  896. 'a':
  897. begin
  898. n := 1;
  899. if ParseControlSequenceParams_Int('HPR', n) then
  900. begin
  901. FModel.SetCursorPos(Min(FModel.CursorX + Max(n, 1), CursorLimitY), FModel.CursorY);
  902. FNextCharacterWrapsToNextLine := False;
  903. end;
  904. end;
  905. { REP - REPEAT }
  906. 'b':
  907. begin
  908. n := 1;
  909. if ParseControlSequenceParams_Int('REP', n) then
  910. begin
  911. if FLastGraphicCharacter <> '' then
  912. WriteRepeatedCharacter(FLastGraphicCharacter, Max(n, 1));
  913. FLastGraphicCharacter := '';
  914. end;
  915. end;
  916. { DA - DEVICE ATTRIBUTES }
  917. 'c':
  918. begin
  919. if (Length(FControlSequenceParameter) >= 1) and (FControlSequenceParameter[1] = '>') then
  920. begin
  921. { Secondary DA }
  922. Delete(FControlSequenceParameter, 1, 1);
  923. n := 0;
  924. if ParseControlSequenceParams_Int('Secondary DA', n) then
  925. TransmitStr(EncodeReturnC1(C1_CSI) + '>41;371;0c');
  926. end
  927. else
  928. if (Length(FControlSequenceParameter) >= 1) and (FControlSequenceParameter[1] = '=') then
  929. begin
  930. { Tertiary DA }
  931. Delete(FControlSequenceParameter, 1, 1);
  932. n := 0;
  933. if ParseControlSequenceParams_Int('Tertiary DA', n) then
  934. TransmitStr(EncodeReturnC1(C1_DCS) + '!|00000000' + EncodeReturnC1(C1_ST));
  935. end
  936. else
  937. begin
  938. { Primary DA }
  939. n := 0;
  940. if ParseControlSequenceParams_Int('DA', n) then
  941. begin
  942. case TerminalType of
  943. ttVT100:
  944. TransmitStr(EncodeReturnC1(C1_CSI) + '?1;2c');
  945. ttVT101:
  946. TransmitStr(EncodeReturnC1(C1_CSI) + '?1;0c');
  947. ttVT102:
  948. TransmitStr(EncodeReturnC1(C1_CSI) + '?6c');
  949. ttVT125:
  950. TransmitStr(EncodeReturnC1(C1_CSI) + '?12;2;0;372c');
  951. ttVT131:
  952. TransmitStr(EncodeReturnC1(C1_CSI) + '?7c');
  953. ttVT132:
  954. TransmitStr(EncodeReturnC1(C1_CSI) + '?4;2c');
  955. ttVT220:
  956. TransmitStr(EncodeReturnC1(C1_CSI) + '?62;1;2;6;9;15;16;22;28c');
  957. ttVT240,
  958. ttVT241:
  959. TransmitStr(EncodeReturnC1(C1_CSI) + '?62;1;2;4;6;9;15;16;22;28c');
  960. ttVT320:
  961. TransmitStr(EncodeReturnC1(C1_CSI) + '?63;1;2;6;9;15;16;22;28c');
  962. ttVT330,
  963. ttVT340,
  964. ttVT382:
  965. TransmitStr(EncodeReturnC1(C1_CSI) + '?63;1;2;4;6;9;15;16;22;28c');
  966. ttVT420:
  967. TransmitStr(EncodeReturnC1(C1_CSI) + '?64;1;2;6;9;15;16;17;18;21;22;28c');
  968. ttVT510,
  969. ttVT520,
  970. ttVT525:
  971. TransmitStr(EncodeReturnC1(C1_CSI) + '?65;1;2;6;9;15;16;17;18;21;22;28c');
  972. end;
  973. end;
  974. end;
  975. end;
  976. { VPA - LINE POSITION ABSOLUTE }
  977. 'd':
  978. begin
  979. n := 1;
  980. if ParseControlSequenceParams_Int('VPA', n) then
  981. begin
  982. FModel.SetCursorPos(FModel.CursorX, EnsureRange(CursorOriginY + Max(n, 1) - 1, CursorMinY, CursorLimitY));
  983. FNextCharacterWrapsToNextLine := False;
  984. end;
  985. end;
  986. { VPR - LINE POSITION FORWARD }
  987. 'e':
  988. begin
  989. n := 1;
  990. if ParseControlSequenceParams_Int('VPR', n) then
  991. begin
  992. FModel.SetCursorPos(FModel.CursorX, Min(FModel.CursorY + Max(n, 1), CursorLimitY));
  993. FNextCharacterWrapsToNextLine := False;
  994. end;
  995. end;
  996. { HVP - CHARACTER AND LINE POSITION }
  997. 'f':
  998. begin
  999. n := 1;
  1000. m := 1;
  1001. if ParseControlSequenceParams_Int_Int('HVP', n, m) then
  1002. begin
  1003. FModel.SetCursorPos(EnsureRange(CursorHomeX + Max(m, 1) - 1, CursorMinX, CursorLimitX), EnsureRange(CursorHomeY + Max(n, 1) - 1, CursorMinY, CursorLimitY));
  1004. FNextCharacterWrapsToNextLine := False;
  1005. end;
  1006. end;
  1007. { TBC - TABULATION CLEAR }
  1008. 'g':
  1009. begin
  1010. n := 0;
  1011. if ParseControlSequenceParams_Int('TBC', n) then
  1012. case n of
  1013. 0:
  1014. FTabStops[FModel.CursorX] := False;
  1015. 3:
  1016. FTabStops.Clear;
  1017. else
  1018. FLogger.LogMessage(vlWarning, 'Unhandled TBC: ' + IntToStr(n));
  1019. end;
  1020. end;
  1021. { SM - SET MODE }
  1022. 'h':
  1023. begin
  1024. if (Length(FControlSequenceParameter) > 1) and (FControlSequenceParameter[1] = '?') then
  1025. begin
  1026. { DEC Private Mode Set (DECSET) }
  1027. Delete(FControlSequenceParameter, 1, 1);
  1028. while FControlSequenceParameter <> '' do
  1029. begin
  1030. n := ExtractIntParameter(FControlSequenceParameter, -1);
  1031. case n of
  1032. 1:
  1033. Include(FModeFlags, tmfCursorKeysSendApplicationSequences);
  1034. 3:
  1035. if tmfAllow80To132ModeSwitching in FModeFlags then
  1036. begin
  1037. FScrollingRegionTop := 0;
  1038. FScrollingRegionBottom := FModel.Height - 1;
  1039. FScrollingRegionLeft := 0;
  1040. FScrollingRegionRight := FModel.Width - 1;
  1041. FModel.SetCursorPos(CursorHomeX, CursorHomeY);
  1042. ErasePage;
  1043. Resize(132, FModel.Height);
  1044. end;
  1045. 5:
  1046. begin
  1047. Include(FModeFlags, tmfReverseVideo);
  1048. FModel.ReverseVideo := True;
  1049. end;
  1050. 6:
  1051. begin
  1052. Include(FModeFlags, tmfOriginMode);
  1053. FModel.SetCursorPos(CursorHomeX, CursorHomeY);
  1054. end;
  1055. 7:
  1056. Include(FModeFlags, tmfAutoWrapMode);
  1057. 9:
  1058. FMouseTrackingMode := tmtmX10;
  1059. 12:
  1060. FModel.StartBlinkingCursor;
  1061. 25:
  1062. FModel.ShowCursor;
  1063. 40:
  1064. Include(FModeFlags, tmfAllow80To132ModeSwitching);
  1065. 1000:
  1066. FMouseTrackingMode := tmtmNormal;
  1067. 1002:
  1068. FMouseTrackingMode := tmtmButtonEvent;
  1069. 1003:
  1070. FMouseTrackingMode := tmtmAnyEvent;
  1071. 1005:
  1072. FMouseProtocolEncoding := tmpeUTF8;
  1073. 1006:
  1074. FMouseProtocolEncoding := tmpeSGR;
  1075. 1049:
  1076. begin
  1077. SaveCursor;
  1078. FModel.CurrentVisibleScreenBuffer := sbAlternate;
  1079. end;
  1080. 2004:
  1081. Include(FModeFlags, tmfBracketedPasteMode);
  1082. else
  1083. FLogger.LogMessage(vlWarning, 'Unhandled DECSET: ' + IntToStr(n));
  1084. end;
  1085. end;
  1086. end
  1087. else
  1088. begin
  1089. while FControlSequenceParameter <> '' do
  1090. begin
  1091. n := ExtractIntParameter(FControlSequenceParameter, -1);
  1092. case n of
  1093. 2:
  1094. Include(FModeFlags, tmfKeyboardActionMode);
  1095. 4:
  1096. Include(FModeFlags, tmfInsertMode);
  1097. 12:
  1098. Include(FModeFlags, tmfSendReceiveMode);
  1099. 20:
  1100. Include(FModeFlags, tmfAutoNewLine);
  1101. else
  1102. FLogger.LogMessage(vlWarning, 'Unhandled SET MODE: ' + IntToStr(n));
  1103. end;
  1104. end;
  1105. end;
  1106. end;
  1107. { VPB - LINE POSITION BACKWARD }
  1108. {'k':
  1109. begin
  1110. n := 1;
  1111. if ParseControlSequenceParams_Int('VPB', n) then
  1112. FModel.SetCursorPos(FModel.CursorX, Max(FModel.CursorY - Max(n, 1), 0));
  1113. end;}
  1114. { RM - RESET MODE }
  1115. 'l':
  1116. begin
  1117. if (Length(FControlSequenceParameter) > 1) and (FControlSequenceParameter[1] = '?') then
  1118. begin
  1119. { DEC Private Mode Reset (DECRST) }
  1120. Delete(FControlSequenceParameter, 1, 1);
  1121. while FControlSequenceParameter <> '' do
  1122. begin
  1123. n := ExtractIntParameter(FControlSequenceParameter, -1);
  1124. case n of
  1125. 1:
  1126. Exclude(FModeFlags, tmfCursorKeysSendApplicationSequences);
  1127. 2:
  1128. EnterVT52Mode;
  1129. 3:
  1130. if tmfAllow80To132ModeSwitching in FModeFlags then
  1131. begin
  1132. FScrollingRegionTop := 0;
  1133. FScrollingRegionBottom := FModel.Height - 1;
  1134. FScrollingRegionLeft := 0;
  1135. FScrollingRegionRight := FModel.Width - 1;
  1136. FModel.SetCursorPos(CursorHomeX, CursorHomeY);
  1137. ErasePage;
  1138. Resize(80, FModel.Height);
  1139. end;
  1140. 5:
  1141. begin
  1142. Exclude(FModeFlags, tmfReverseVideo);
  1143. FModel.ReverseVideo := False;
  1144. end;
  1145. 6:
  1146. begin
  1147. Exclude(FModeFlags, tmfOriginMode);
  1148. FModel.SetCursorPos(CursorHomeX, CursorHomeY);
  1149. end;
  1150. 7:
  1151. Exclude(FModeFlags, tmfAutoWrapMode);
  1152. 9:
  1153. FMouseTrackingMode := tmtmNone;
  1154. 12:
  1155. FModel.StopBlinkingCursor;
  1156. 25:
  1157. FModel.HideCursor;
  1158. 40:
  1159. Exclude(FModeFlags, tmfAllow80To132ModeSwitching);
  1160. 1000:
  1161. FMouseTrackingMode := tmtmNone;
  1162. 1002:
  1163. FMouseTrackingMode := tmtmNone;
  1164. 1003:
  1165. FMouseTrackingMode := tmtmNone;
  1166. 1005:
  1167. FMouseProtocolEncoding := tmpeX10;
  1168. 1006:
  1169. FMouseProtocolEncoding := tmpeX10;
  1170. 1049:
  1171. begin
  1172. FModel.CurrentVisibleScreenBuffer := sbNormal;
  1173. RestoreCursor;
  1174. end;
  1175. 2004:
  1176. Exclude(FModeFlags, tmfBracketedPasteMode);
  1177. else
  1178. FLogger.LogMessage(vlWarning, 'Unhandled DECRST: ' + IntToStr(n));
  1179. end;
  1180. end;
  1181. end
  1182. else
  1183. begin
  1184. while FControlSequenceParameter <> '' do
  1185. begin
  1186. n := ExtractIntParameter(FControlSequenceParameter, -1);
  1187. case n of
  1188. 2:
  1189. Exclude(FModeFlags, tmfKeyboardActionMode);
  1190. 4:
  1191. Exclude(FModeFlags, tmfInsertMode);
  1192. 12:
  1193. Exclude(FModeFlags, tmfSendReceiveMode);
  1194. 20:
  1195. Exclude(FModeFlags, tmfAutoNewLine);
  1196. else
  1197. FLogger.LogMessage(vlWarning, 'Unhandled RESET MODE: ' + IntToStr(n));
  1198. end;
  1199. end;
  1200. end;
  1201. end;
  1202. { SGR - SELECT GRAPHIC RENDITION }
  1203. 'm':
  1204. HandleSGR;
  1205. { DSR - DEVICE STATUS REPORT }
  1206. 'n':
  1207. begin
  1208. if (Length(FControlSequenceParameter) > 1) and (FControlSequenceParameter[1] = '?') then
  1209. begin
  1210. { DSR, DEC format }
  1211. Delete(FControlSequenceParameter, 1, 1);
  1212. n := -1;
  1213. if ParseControlSequenceParams_Int('DSR_DEC', n) then
  1214. case n of
  1215. 6:
  1216. if FDecConformanceLevel >= dclVT400 then
  1217. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(FModel.CursorY - CursorOriginY + 1) + ';' + IntToStr(FModel.CursorX - CursorOriginX + 1) + ';1R')
  1218. else
  1219. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(FModel.CursorY - CursorOriginY + 1) + ';' + IntToStr(FModel.CursorX - CursorOriginX + 1) + 'R');
  1220. { Report Printer status }
  1221. 15:
  1222. if FDecConformanceLevel >= dclVT200 then
  1223. TransmitStr(EncodeReturnC1(C1_CSI) + '?13n'); { No printer }
  1224. { Report UDK (User Defined Keys) status }
  1225. 25:
  1226. if FDecConformanceLevel >= dclVT200 then
  1227. TransmitStr(EncodeReturnC1(C1_CSI) + '?20n'); { UDKs unlocked }
  1228. { Report Keyboard status }
  1229. 26:
  1230. if FDecConformanceLevel >= dclVT400 then
  1231. TransmitStr(EncodeReturnC1(C1_CSI) + '?27;1;0;0n')
  1232. else if FDecConformanceLevel >= dclVT300 then
  1233. TransmitStr(EncodeReturnC1(C1_CSI) + '?27;1;0n')
  1234. else if FDecConformanceLevel >= dclVT200 then
  1235. TransmitStr(EncodeReturnC1(C1_CSI) + '?27;1n');
  1236. { Report Locator status }
  1237. 53, 55:
  1238. if FDecConformanceLevel >= dclVT300 then
  1239. TransmitStr(EncodeReturnC1(C1_CSI) + '?53n'); { No locator }
  1240. { Report Locator type }
  1241. 56:
  1242. if FDecConformanceLevel >= dclVT300 then
  1243. TransmitStr(EncodeReturnC1(C1_CSI) + '?57;0n'); { Cannot identify }
  1244. else
  1245. FLogger.LogMessage(vlWarning, 'Unhandled DEC DEVICE STATUS REPORT: ' + IntToStr(n));
  1246. end;
  1247. end
  1248. else
  1249. begin
  1250. { DSR, ANSI format }
  1251. n := -1;
  1252. if ParseControlSequenceParams_Int('DSR_ANSI', n) then
  1253. case n of
  1254. 5:
  1255. TransmitStr(EncodeReturnC1(C1_CSI) + '0n');
  1256. 6:
  1257. TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(FModel.CursorY - CursorOriginY + 1) + ';' + IntToStr(FModel.CursorX - CursorOriginX + 1) + 'R');
  1258. else
  1259. FLogger.LogMessage(vlWarning, 'Unhandled ANSI DEVICE STATUS REPORT: ' + IntToStr(n));
  1260. end;
  1261. end;
  1262. end;
  1263. 'p':
  1264. begin
  1265. if FControlSequenceIntermediate = '"' then
  1266. begin
  1267. { DECSCL - Select Conformance Level (VT220+) }
  1268. if TerminalType >= ttVT220 then
  1269. begin
  1270. FControlSequenceIntermediate := '';
  1271. n := 0; { todo:??? }
  1272. m := 0; { todo:??? }
  1273. if ParseControlSequenceParams_Int_Int('DECSCL', n, m) then
  1274. begin
  1275. case n of
  1276. 61:
  1277. begin
  1278. FDecConformanceLevel := dclVT100;
  1279. m := 1;
  1280. end;
  1281. 62:
  1282. FDecConformanceLevel := dclVT200;
  1283. 63:
  1284. FDecConformanceLevel := dclVT300;
  1285. 64:
  1286. FDecConformanceLevel := dclVT400;
  1287. 65:
  1288. FDecConformanceLevel := dclVT500;
  1289. end;
  1290. if FDecConformanceLevel > MaxConformanceLevelForTerminal[TerminalType] then
  1291. FDecConformanceLevel := MaxConformanceLevelForTerminal[TerminalType];
  1292. case m of
  1293. 0, 2:
  1294. Include(FModeFlags, tmfSend8BitC1Controls);
  1295. 1:
  1296. Exclude(FModeFlags, tmfSend8BitC1Controls);
  1297. end;
  1298. { todo: soft or hard reset? }
  1299. end
  1300. else
  1301. FLogger.LogMessage(vlWarning, 'Unhandled CSI control sequence: ' + FControlSequenceParameter + '"' + FControlSequenceFinalByte);
  1302. end;
  1303. end
  1304. else if FControlSequenceIntermediate = '$' then
  1305. begin
  1306. { DECRQM - Request ANSI/DEC private mode (VT300+) }
  1307. if FDecConformanceLevel >= dclVT300 then
  1308. begin
  1309. FControlSequenceIntermediate := '';
  1310. if (Length(FControlSequenceParameter) > 1) and (FControlSequenceParameter[1] = '?') then
  1311. begin
  1312. { Request DEC private mode }
  1313. Delete(FControlSequenceParameter, 1, 1);
  1314. n := 65535;
  1315. if ParseControlSequenceParams_Int('DECRQM', n) then
  1316. case n of
  1317. 1:
  1318. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfCursorKeysSendApplicationSequences in FModeFlags, 1, 2)) + '$y');
  1319. 2:
  1320. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';1$y');
  1321. 3:
  1322. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(FModel.Width >= 132, 1, 2)) + '$y');
  1323. 5:
  1324. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfReverseVideo in FModeFlags, 1, 2)) + '$y');
  1325. 6:
  1326. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfOriginMode in FModeFlags, 1, 2)) + '$y');
  1327. 7:
  1328. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfAutoWrapMode in FModeFlags, 1, 2)) + '$y');
  1329. 25:
  1330. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(FModel.CursorVisible, 1, 2)) + '$y');
  1331. 40:
  1332. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';' + IntToStr(IfThen(tmfAllow80To132ModeSwitching in FModeFlags, 1, 2)) + '$y');
  1333. { permanently reset }
  1334. 8: { DECARM }
  1335. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';4$y');
  1336. { permanently set }
  1337. 14: { DECTEM }
  1338. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';3$y');
  1339. else
  1340. TransmitStr(EncodeReturnC1(C1_CSI) + '?' + IntToStr(n) + ';0$y');
  1341. end;
  1342. end
  1343. else
  1344. begin
  1345. { Request ANSI mode }
  1346. n := 65535;
  1347. if ParseControlSequenceParams_Int('DECRQM', n) then
  1348. case n of
  1349. 2:
  1350. TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';' + IntToStr(IfThen(tmfKeyboardActionMode in FModeFlags, 1, 2)) + '$y');
  1351. 3:
  1352. TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';2$y');
  1353. 4:
  1354. TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';' + IntToStr(IfThen(tmfInsertMode in FModeFlags, 1, 2)) + '$y');
  1355. 12:
  1356. TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';' + IntToStr(IfThen(tmfSendReceiveMode in FModeFlags, 1, 2)) + '$y');
  1357. 20:
  1358. TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';' + IntToStr(IfThen(tmfAutoNewLine in FModeFlags, 1, 2)) + '$y');
  1359. { permanently reset }
  1360. 1, { GATM }
  1361. 5, { KAM }
  1362. 7, { SRTM }
  1363. 10, { VEM }
  1364. 11, { HEM }
  1365. 13, { PUM }
  1366. 14, { SRM }
  1367. 15, { FEAM }
  1368. 16, { TTM }
  1369. 17, { SATM }
  1370. 18, { TSM }
  1371. 19: { EBM }
  1372. TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';4$y');
  1373. else
  1374. TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n) + ';0$y');
  1375. end;
  1376. end;
  1377. end;
  1378. end
  1379. else if FControlSequenceIntermediate = '!' then
  1380. begin
  1381. { DECSTR - Soft Terminal Reset (VT220+) }
  1382. if FDecConformanceLevel >= dclVT200 then
  1383. begin
  1384. SoftReset;
  1385. end;
  1386. end
  1387. else
  1388. FLogger.LogMessage(vlWarning, 'Unhandled CSI control sequence: ' + FControlSequenceParameter + FControlSequenceIntermediate + FControlSequenceFinalByte);
  1389. end;
  1390. { DECSTBM - Set Top and Bottom Margins }
  1391. 'r':
  1392. begin
  1393. n := 1;
  1394. m := FModel.Height;
  1395. if ParseControlSequenceParams_Int_Int('DECSTBM', n, m) then
  1396. begin
  1397. if n = 0 then
  1398. n := 1;
  1399. if m = 0 then
  1400. m := FModel.Height;
  1401. if n > FModel.Height then
  1402. n := FModel.Height;
  1403. if m > FModel.Height then
  1404. m := FModel.Height;
  1405. if n < m then
  1406. begin
  1407. FScrollingRegionTop := n - 1;
  1408. FScrollingRegionBottom := m - 1;
  1409. FModel.SetCursorPos(CursorHomeX, CursorHomeY);
  1410. end;
  1411. end;
  1412. end;
  1413. { DECREQTPARM - Request Terminal Parameters }
  1414. 'x':
  1415. begin
  1416. n := 0;
  1417. if ParseControlSequenceParams_Int('DECREQTPARM', n) then
  1418. begin
  1419. case n of
  1420. 0, 1:
  1421. begin
  1422. TransmitStr(EncodeReturnC1(C1_CSI) + IntToStr(n + 2) + ';1;1;120;120;1;0x');
  1423. end;
  1424. end;
  1425. end;
  1426. end;
  1427. else
  1428. FLogger.LogMessage(vlWarning, 'Unhandled CSI control sequence: ' + FControlSequenceParameter + FControlSequenceIntermediate + FControlSequenceFinalByte);
  1429. end;
  1430. end;
  1431. procedure TTerminalController.ExecuteOSC;
  1432. begin
  1433. {...}
  1434. FLogger.LogMessage(vlWarning, 'Unhandled OSC control sequence: ' + FOperatingSystemCommand);
  1435. end;
  1436. procedure TTerminalController.ExecuteDCS;
  1437. begin
  1438. if (Length(FDeviceControlString) >= 2) and (FDeviceControlString[1] = '$') and (FDeviceControlString[2] = 'q') then
  1439. ExecuteDECRQSS(Copy(FDeviceControlString, 3, Length(FDeviceControlString) - 2))
  1440. else
  1441. FLogger.LogMessage(vlWarning, 'Unhandled DCS control sequence: ' + FDeviceControlString);
  1442. end;
  1443. procedure TTerminalController.ExecuteDECRQSS(const ReqStr: string);
  1444. function ConformanceLevel2ID: Integer;
  1445. begin
  1446. case FDecConformanceLevel of
  1447. dclVT200:
  1448. Result := 62;
  1449. dclVT300:
  1450. Result := 63;
  1451. dclVT400:
  1452. Result := 64;
  1453. dclVT500:
  1454. Result := 65;
  1455. else
  1456. Result := -1;
  1457. end;
  1458. end;
  1459. function GetSGRString: string;
  1460. begin
  1461. Result := '0';
  1462. if rfBold in FAttribute.RenditionFlags then
  1463. Result := Result + ';1';
  1464. if rfFaint in FAttribute.RenditionFlags then
  1465. Result := Result + ';2';
  1466. if rfItalicized in FAttribute.RenditionFlags then
  1467. Result := Result + ';3';
  1468. if rfUnderlined in FAttribute.RenditionFlags then
  1469. Result := Result + ';4';
  1470. if rfBlinkSlow in FAttribute.RenditionFlags then
  1471. Result := Result + ';5';
  1472. if rfBlinkFast in FAttribute.RenditionFlags then
  1473. Result := Result + ';6';
  1474. if rfInverse in FAttribute.RenditionFlags then
  1475. Result := Result + ';7';
  1476. if rfInvisible in FAttribute.RenditionFlags then
  1477. Result := Result + ';8';
  1478. if rfCrossedOut in FAttribute.RenditionFlags then
  1479. Result := Result + ';9';
  1480. if rfDoublyUnderlined in FAttribute.RenditionFlags then
  1481. Result := Result + ';21';
  1482. case FAttribute.ForegroundColor of
  1483. cDefaultForeground,
  1484. cDefaultBackground:
  1485. ;
  1486. cBlack:
  1487. Result := Result + ';30';
  1488. cRed:
  1489. Result := Result + ';31';
  1490. cGreen:
  1491. Result := Result + ';32';
  1492. cBrown:
  1493. Result := Result + ';33';
  1494. cBlue:
  1495. Result := Result + ';34';
  1496. cMagenta:
  1497. Result := Result + ';35';
  1498. cCyan:
  1499. Result := Result + ';36';
  1500. cLightGray:
  1501. Result := Result + ';37';
  1502. cDarkGray:
  1503. Result := Result + ';90';
  1504. cLightRed:
  1505. Result := Result + ';91';
  1506. cLightGreen:
  1507. Result := Result + ';92';
  1508. cYellow:
  1509. Result := Result + ';93';
  1510. cLightBlue:
  1511. Result := Result + ';94';
  1512. cLightMagenta:
  1513. Result := Result + ';95';
  1514. cLightCyan:
  1515. Result := Result + ';96';
  1516. cWhite:
  1517. Result := Result + ';97';
  1518. cColor16..cColor255:
  1519. Result := Result + ';38:5:' + IntToStr(Ord(FAttribute.ForegroundColor) - (Ord(cColor16) - 16));
  1520. end;
  1521. case FAttribute.BackgroundColor of
  1522. cDefaultForeground,
  1523. cDefaultBackground:
  1524. ;
  1525. cBlack:
  1526. Result := Result + ';40';
  1527. cRed:
  1528. Result := Result + ';41';
  1529. cGreen:
  1530. Result := Result + ';42';
  1531. cBrown:
  1532. Result := Result + ';43';
  1533. cBlue:
  1534. Result := Result + ';44';
  1535. cMagenta:
  1536. Result := Result + ';45';
  1537. cCyan:
  1538. Result := Result + ';46';
  1539. cLightGray:
  1540. Result := Result + ';47';
  1541. cDarkGray:
  1542. Result := Result + ';100';
  1543. cLightRed:
  1544. Result := Result + ';101';
  1545. cLightGreen:
  1546. Result := Result + ';102';
  1547. cYellow:
  1548. Result := Result + ';103';
  1549. cLightBlue:
  1550. Result := Result + ';104';
  1551. cLightMagenta:
  1552. Result := Result + ';105';
  1553. cLightCyan:
  1554. Result := Result + ';106';
  1555. cWhite:
  1556. Result := Result + ';107';
  1557. cColor16..cColor255:
  1558. Result := Result + ';48:5:' + IntToStr(Ord(FAttribute.BackgroundColor) - (Ord(cColor16) - 16));
  1559. end;
  1560. end;
  1561. begin
  1562. case ReqStr of
  1563. 'm':
  1564. TransmitStr(EncodeReturnC1(C1_DCS) + '1$r' + GetSGRString + ReqStr + EncodeReturnC1(C1_ST));
  1565. '"p':
  1566. begin
  1567. if FDecConformanceLevel >= dclVT200 then
  1568. TransmitStr(EncodeReturnC1(C1_DCS) + '1$r' + IntToStr(ConformanceLevel2ID) + ';' + IntToStr(IfThen(tmfSend8BitC1Controls in ModeFlags, 0, 1)) + ReqStr + EncodeReturnC1(C1_ST));
  1569. end;
  1570. 'r':
  1571. TransmitStr(EncodeReturnC1(C1_DCS) + '1$r' + IntToStr(FScrollingRegionTop + 1) + ';' + IntToStr(FScrollingRegionBottom + 1) + ReqStr + EncodeReturnC1(C1_ST));
  1572. 's':
  1573. if FDecConformanceLevel >= dclVT400 then
  1574. TransmitStr(EncodeReturnC1(C1_DCS) + '1$r' + IntToStr(FScrollingRegionLeft + 1) + ';' + IntToStr(FScrollingRegionRight + 1) + ReqStr + EncodeReturnC1(C1_ST))
  1575. else
  1576. TransmitStr(EncodeReturnC1(C1_DCS) + '0$r' + EncodeReturnC1(C1_ST));
  1577. else
  1578. begin
  1579. FLogger.LogMessage(vlWarning, 'Unknown/unsupported DECRQSS: ' + ReqStr);
  1580. TransmitStr(EncodeReturnC1(C1_DCS) + '0$r' + EncodeReturnC1(C1_ST));
  1581. end;
  1582. end;
  1583. end;
  1584. procedure TTerminalController.HandleSGRAttribute(SGRAttr: string);
  1585. var
  1586. ExtPara1, ExtPara2: LongInt;
  1587. ExtParas: TStringArray;
  1588. begin
  1589. if SGRAttr = '' then
  1590. SGRAttr := '0';
  1591. if OnlyDigits(SGRAttr) then
  1592. begin
  1593. case StrToInt(SGRAttr) of
  1594. 0: { Normal (default), VT100 }
  1595. FAttribute := DefaultAttribute;
  1596. 1: { Bold, VT100 }
  1597. FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfBold]) - [rfFaint];
  1598. 2: { Faint, decreased intensity, ECMA-48 2nd }
  1599. FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfFaint]) - [rfBold];
  1600. 3: { Italicized, ECMA-48 2nd }
  1601. FAttribute.RenditionFlags := FAttribute.RenditionFlags + [rfItalicized];
  1602. 4: { Underlined, VT100 }
  1603. FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfUnderlined]) - [rfDoublyUnderlined];
  1604. 5: { slowly blinking (less than 150 per minute), VT100, ECMA-48 2nd }
  1605. FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfBlinkSlow]) - [rfBlinkFast];
  1606. 6: { rapidly blinking (150 per minute or more), ECMA-48 2nd }
  1607. FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfBlinkFast]) - [rfBlinkSlow];
  1608. 7: { negative image }
  1609. FAttribute.RenditionFlags := FAttribute.RenditionFlags + [rfInverse];
  1610. 8: { Invisible, i.e., hidden, ECMA-48 2nd, VT300 }
  1611. FAttribute.RenditionFlags := FAttribute.RenditionFlags + [rfInvisible];
  1612. 9: { Crossed-out characters, ECMA-48 3rd }
  1613. FAttribute.RenditionFlags := FAttribute.RenditionFlags + [rfCrossedOut];
  1614. 21: { Doubly-underlined, ECMA-48 3rd }
  1615. FAttribute.RenditionFlags := (FAttribute.RenditionFlags + [rfDoublyUnderlined]) - [rfUnderlined];
  1616. 22: { Normal (neither bold nor faint), ECMA-48 3rd }
  1617. FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfBold, rfFaint];
  1618. 23: { Not italicized, ECMA-48 3rd }
  1619. FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfItalicized];
  1620. 24: { Not underlined, ECMA-48 3rd }
  1621. FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfUnderlined, rfDoublyUnderlined];
  1622. 25: { steady (not blinking), ECMA-48 3rd }
  1623. FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfBlinkSlow, rfBlinkFast];
  1624. 27: { positive (not inverse) }
  1625. FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfInverse];
  1626. 28: { Visible, i.e., not hidden, ECMA-48 3rd, VT300 }
  1627. FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfInvisible];
  1628. 29: { Not crossed-out, ECMA-48 3rd }
  1629. FAttribute.RenditionFlags := FAttribute.RenditionFlags - [rfCrossedOut];
  1630. 30: { Set foreground color to Black }
  1631. FAttribute.ForegroundColor := cBlack;
  1632. 31: { Set foreground color to Red }
  1633. FAttribute.ForegroundColor := cRed;
  1634. 32: { Set foreground color to Green }
  1635. FAttribute.ForegroundColor := cGreen;
  1636. 33: { Set foreground color to Yellow }
  1637. FAttribute.ForegroundColor := cBrown;
  1638. 34: { Set foreground color to Blue }
  1639. FAttribute.ForegroundColor := cBlue;
  1640. 35: { Set foreground color to Magenta }
  1641. FAttribute.ForegroundColor := cMagenta;
  1642. 36: { Set foreground color to Cyan }
  1643. FAttribute.ForegroundColor := cCyan;
  1644. 37: { Set foreground color to White }
  1645. FAttribute.ForegroundColor := cLightGray;
  1646. 39: { Set foreground color to default, ECMA-48 3rd }
  1647. FAttribute.ForegroundColor := cDefaultForeground;
  1648. 40: { Set background color to Black }
  1649. FAttribute.BackgroundColor := cBlack;
  1650. 41: { Set background color to Red }
  1651. FAttribute.BackgroundColor := cRed;
  1652. 42: { Set background color to Green }
  1653. FAttribute.BackgroundColor := cGreen;
  1654. 43: { Set background color to Yellow }
  1655. FAttribute.BackgroundColor := cBrown;
  1656. 44: { Set background color to Blue }
  1657. FAttribute.BackgroundColor := cBlue;
  1658. 45: { Set background color to Magenta }
  1659. FAttribute.BackgroundColor := cMagenta;
  1660. 46: { Set background color to Cyan }
  1661. FAttribute.BackgroundColor := cCyan;
  1662. 47: { Set background color to White }
  1663. FAttribute.BackgroundColor := cLightGray;
  1664. 49: { Set background color to default, ECMA-48 3rd }
  1665. FAttribute.BackgroundColor := cDefaultBackground;
  1666. 90: { Set foreground color to Black }
  1667. FAttribute.ForegroundColor := cDarkGray;
  1668. 91: { Set foreground color to Red }
  1669. FAttribute.ForegroundColor := cLightRed;
  1670. 92: { Set foreground color to Green }
  1671. FAttribute.ForegroundColor := cLightGreen;
  1672. 93: { Set foreground color to Yellow }
  1673. FAttribute.ForegroundColor := cYellow;
  1674. 94: { Set foreground color to Blue }
  1675. FAttribute.ForegroundColor := cLightBlue;
  1676. 95: { Set foreground color to Magenta }
  1677. FAttribute.ForegroundColor := cLightMagenta;
  1678. 96: { Set foreground color to Cyan }
  1679. FAttribute.ForegroundColor := cLightCyan;
  1680. 97: { Set foreground color to White }
  1681. FAttribute.ForegroundColor := cWhite;
  1682. 100: { Set background color to Black }
  1683. FAttribute.BackgroundColor := cDarkGray;
  1684. 101: { Set background color to Red }
  1685. FAttribute.BackgroundColor := cLightRed;
  1686. 102: { Set background color to Green }
  1687. FAttribute.BackgroundColor := cLightGreen;
  1688. 103: { Set background color to Yellow }
  1689. FAttribute.BackgroundColor := cYellow;
  1690. 104: { Set background color to Blue }
  1691. FAttribute.BackgroundColor := cLightBlue;
  1692. 105: { Set background color to Magenta }
  1693. FAttribute.BackgroundColor := cLightMagenta;
  1694. 106: { Set background color to Cyan }
  1695. FAttribute.BackgroundColor := cLightCyan;
  1696. 107: { Set background color to White }
  1697. FAttribute.BackgroundColor := cWhite;
  1698. else
  1699. FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
  1700. end;
  1701. end
  1702. else
  1703. begin
  1704. if Pos(':', SGRAttr) <> 0 then
  1705. begin
  1706. ExtParas := SGRAttr.Split(':');
  1707. ExtPara1 := StrToIntDef(ExtParas[0], 0);
  1708. case ExtPara1 of
  1709. 38,
  1710. 48:
  1711. begin
  1712. ExtPara2 := StrToIntDef(ExtParas[1], 0);
  1713. case ExtPara2 of
  1714. 2:
  1715. begin
  1716. if Length(ExtParas) = 5 then
  1717. begin
  1718. if ExtPara1 = 38 then
  1719. FAttribute.SetForegroundColorRGB(StrToIntDef(ExtParas[2], 0), StrToIntDef(ExtParas[3], 0), StrToIntDef(ExtParas[4], 0))
  1720. else if ExtPara1 = 48 then
  1721. FAttribute.SetBackgroundColorRGB(StrToIntDef(ExtParas[2], 0), StrToIntDef(ExtParas[3], 0), StrToIntDef(ExtParas[4], 0));
  1722. end
  1723. else if Length(ExtParas) >= 6 then
  1724. begin
  1725. if ExtPara1 = 38 then
  1726. FAttribute.SetForegroundColorRGB(StrToIntDef(ExtParas[3], 0), StrToIntDef(ExtParas[4], 0), StrToIntDef(ExtParas[5], 0))
  1727. else if ExtPara1 = 48 then
  1728. FAttribute.SetBackgroundColorRGB(StrToIntDef(ExtParas[3], 0), StrToIntDef(ExtParas[4], 0), StrToIntDef(ExtParas[5], 0));
  1729. end
  1730. else
  1731. FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
  1732. end;
  1733. 5:
  1734. begin
  1735. if ExtPara1 = 38 then
  1736. FAttribute.ForegroundColor := TColor(StrToIntDef(ExtParas[2], 0))
  1737. else if ExtPara1 = 48 then
  1738. FAttribute.BackgroundColor := TColor(StrToIntDef(ExtParas[2], 0));
  1739. end;
  1740. else
  1741. FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
  1742. end;
  1743. end;
  1744. else
  1745. FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
  1746. end;
  1747. end
  1748. else
  1749. FLogger.LogMessage(vlWarning, 'Unhandled SGR attribute: ' + SGRAttr);
  1750. end;
  1751. end;
  1752. procedure TTerminalController.ScrollUp(LinesCount: Integer);
  1753. var
  1754. X, Y: Integer;
  1755. begin
  1756. if LinesCount < 0 then
  1757. exit;
  1758. if LinesCount = 0 then
  1759. LinesCount := 1;
  1760. for Y := FScrollingRegionTop to FScrollingRegionBottom - LinesCount do
  1761. for X := FScrollingRegionLeft to FScrollingRegionRight do
  1762. FModel.Cell[Y, X] := FModel.Cell[Y + LinesCount, X];
  1763. for Y := Max(FScrollingRegionBottom - LinesCount + 1, FScrollingRegionTop) to FScrollingRegionBottom do
  1764. for X := FScrollingRegionLeft to FScrollingRegionRight do
  1765. FModel.Cell[Y, X] := ErasedCell(FAttribute);
  1766. end;
  1767. procedure TTerminalController.ScrollDown(LinesCount: Integer);
  1768. var
  1769. X, Y: Integer;
  1770. begin
  1771. if LinesCount < 0 then
  1772. exit;
  1773. if LinesCount = 0 then
  1774. LinesCount := 1;
  1775. for Y := FScrollingRegionBottom downto FScrollingRegionTop + LinesCount do
  1776. for X := FScrollingRegionLeft to FScrollingRegionRight do
  1777. FModel.Cell[Y, X] := FModel.Cell[Y - LinesCount, X];
  1778. for Y := FScrollingRegionTop to Min(FScrollingRegionTop + LinesCount - 1, FScrollingRegionBottom) do
  1779. for X := FScrollingRegionLeft to FScrollingRegionRight do
  1780. FModel.Cell[Y, X] := ErasedCell(FAttribute);
  1781. end;
  1782. procedure TTerminalController.ScrollLeft(CharCount: Integer);
  1783. var
  1784. Y, X: Integer;
  1785. begin
  1786. if CharCount < 0 then
  1787. exit;
  1788. if CharCount = 0 then
  1789. CharCount := 1;
  1790. for Y := FScrollingRegionTop to FScrollingRegionBottom do
  1791. begin
  1792. for X := 0 to FModel.Width - CharCount - 1 do
  1793. FModel.Cell[Y, X] := FModel.Cell[Y, X + CharCount];
  1794. for X := Max(0, FModel.Width - CharCount) to FModel.Width - 1 do
  1795. FModel.Cell[Y, X] := ErasedCell(FAttribute);
  1796. end;
  1797. end;
  1798. procedure TTerminalController.ScrollRight(CharCount: Integer);
  1799. var
  1800. Y, X: Integer;
  1801. begin
  1802. if CharCount < 0 then
  1803. exit;
  1804. if CharCount = 0 then
  1805. CharCount := 1;
  1806. for Y := FScrollingRegionTop to FScrollingRegionBottom do
  1807. begin
  1808. for X := FModel.Width - 1 downto CharCount do
  1809. FModel.Cell[Y, X] := FModel.Cell[Y, X - CharCount];
  1810. for X := 0 to Min(CharCount - 1, FModel.Width - 1) do
  1811. FModel.Cell[Y, X] := ErasedCell(FAttribute);
  1812. end;
  1813. end;
  1814. procedure TTerminalController.InsertLines(LinesCount: Integer);
  1815. var
  1816. X, Y: Integer;
  1817. begin
  1818. if LinesCount < 0 then
  1819. exit;
  1820. if LinesCount = 0 then
  1821. LinesCount := 1;
  1822. if LinesCount > (FScrollingRegionBottom - FModel.CursorY + 1) then
  1823. LinesCount := FScrollingRegionBottom - FModel.CursorY + 1;
  1824. for Y := FScrollingRegionBottom downto FModel.CursorY + LinesCount do
  1825. for X := 0 to FModel.Width - 1 do
  1826. FModel.Cell[Y, X] := FModel.Cell[Y - LinesCount, X];
  1827. for Y := FModel.CursorY to FModel.CursorY + LinesCount - 1 do
  1828. for X := 0 to FModel.Width - 1 do
  1829. FModel.Cell[Y, X] := ErasedCell(FAttribute);
  1830. FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
  1831. end;
  1832. procedure TTerminalController.DeleteLines(LinesCount: Integer);
  1833. var
  1834. X, Y: Integer;
  1835. begin
  1836. if LinesCount < 0 then
  1837. exit;
  1838. if LinesCount = 0 then
  1839. LinesCount := 1;
  1840. if LinesCount > (FScrollingRegionBottom - FModel.CursorY + 1) then
  1841. LinesCount := FScrollingRegionBottom - FModel.CursorY + 1;
  1842. for Y := FModel.CursorY to FScrollingRegionBottom - LinesCount do
  1843. for X := 0 to FModel.Width - 1 do
  1844. FModel.Cell[Y, X] := FModel.Cell[Y + LinesCount, X];
  1845. for Y := FScrollingRegionBottom - LinesCount + 1 to FScrollingRegionBottom do
  1846. for X := 0 to FModel.Width - 1 do
  1847. FModel.Cell[Y, X] := ErasedCell(FAttribute);
  1848. FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
  1849. end;
  1850. procedure TTerminalController.DeleteCharacters(CharCount: Integer);
  1851. var
  1852. X: Integer;
  1853. begin
  1854. for X := FModel.CursorX to FModel.Width - 1 do
  1855. if (X + CharCount) < FModel.Width then
  1856. FModel.Cell[FModel.CursorY, X] := FModel.Cell[FModel.CursorY, X + CharCount]
  1857. else
  1858. FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
  1859. FNextCharacterWrapsToNextLine := False;
  1860. end;
  1861. procedure TTerminalController.ErasePage;
  1862. var
  1863. X, Y: Integer;
  1864. begin
  1865. for Y := 0 to FModel.Height - 1 do
  1866. for X := 0 to FModel.Width - 1 do
  1867. FModel.Cell[Y, X] := ErasedCell(FAttribute);
  1868. FNextCharacterWrapsToNextLine := False;
  1869. end;
  1870. procedure TTerminalController.ErasePageToBottom;
  1871. var
  1872. X, Y: Integer;
  1873. begin
  1874. for X := FModel.CursorX to FModel.Width - 1 do
  1875. FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
  1876. for Y := FModel.CursorY + 1 to FModel.Height - 1 do
  1877. for X := 0 to FModel.Width - 1 do
  1878. FModel.Cell[Y, X] := ErasedCell(FAttribute);
  1879. FNextCharacterWrapsToNextLine := False;
  1880. end;
  1881. procedure TTerminalController.ErasePageToTop;
  1882. var
  1883. X, Y: Integer;
  1884. begin
  1885. for X := 0 to FModel.CursorX do
  1886. FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
  1887. for Y := 0 to FModel.CursorY - 1 do
  1888. for X := 0 to FModel.Width - 1 do
  1889. FModel.Cell[Y, X] := ErasedCell(FAttribute);
  1890. FNextCharacterWrapsToNextLine := False;
  1891. end;
  1892. procedure TTerminalController.EraseLineToRight;
  1893. var
  1894. X: Integer;
  1895. begin
  1896. for X := FModel.CursorX to FModel.Width - 1 do
  1897. FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
  1898. FNextCharacterWrapsToNextLine := False;
  1899. end;
  1900. procedure TTerminalController.EraseLineToLeft;
  1901. var
  1902. X: Integer;
  1903. begin
  1904. for X := 0 to FModel.CursorX do
  1905. FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
  1906. FNextCharacterWrapsToNextLine := False;
  1907. end;
  1908. procedure TTerminalController.EraseLine;
  1909. var
  1910. X: Integer;
  1911. begin
  1912. for X := 0 to FModel.Width - 1 do
  1913. FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
  1914. FNextCharacterWrapsToNextLine := False;
  1915. end;
  1916. procedure TTerminalController.EraseCharacters(CharCount: Integer);
  1917. var
  1918. X: Integer;
  1919. begin
  1920. if CharCount < 0 then
  1921. exit;
  1922. if CharCount = 0 then
  1923. CharCount := 1;
  1924. for X := FModel.CursorX to Min(FModel.CursorX + CharCount - 1, FModel.Width - 1) do
  1925. FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
  1926. FNextCharacterWrapsToNextLine := False;
  1927. end;
  1928. procedure TTerminalController.InsertBlankCharacters(CharCount: Integer);
  1929. var
  1930. X: Integer;
  1931. begin
  1932. if CharCount < 0 then
  1933. exit;
  1934. if CharCount = 0 then
  1935. CharCount := 1;
  1936. for X := FModel.Width - 1 downto FModel.CursorX + CharCount do
  1937. FModel.Cell[FModel.CursorY, X] := FModel.Cell[FModel.CursorY, X - CharCount];
  1938. for X := FModel.CursorX to Min(FModel.CursorX + CharCount - 1, FModel.Width - 1) do
  1939. FModel.Cell[FModel.CursorY, X] := ErasedCell(FAttribute);
  1940. FNextCharacterWrapsToNextLine := False;
  1941. end;
  1942. procedure TTerminalController.WriteUTF32Char(const UTF32Char: LongWord);
  1943. var
  1944. SaveLastGraphicCharacter: TExtendedGraphemeCluster;
  1945. X: Integer;
  1946. begin
  1947. SaveLastGraphicCharacter := FLastGraphicCharacter;
  1948. FLastGraphicCharacter := '';
  1949. if (UTF32Char >= $D800) and (UTF32Char <= $DFFF) then
  1950. { error }
  1951. exit
  1952. else if UTF32Char <= $FFFF then
  1953. FLastGraphicCharacter := WideChar(UTF32Char)
  1954. else if UTF32Char <= $10FFFF then
  1955. FLastGraphicCharacter := WideChar(((UTF32Char - $10000) shr 10) + $D800) + WideChar(((UTF32Char - $10000) and %1111111111) + $DC00)
  1956. else
  1957. { error }
  1958. exit;
  1959. if (SaveLastGraphicCharacter <> '') and (FModel.StringDisplayWidth(SaveLastGraphicCharacter + FLastGraphicCharacter) <= 1) then
  1960. begin
  1961. { combine with previous character }
  1962. FLastGraphicCharacter := SaveLastGraphicCharacter + FLastGraphicCharacter;
  1963. if FNextCharacterWrapsToNextLine then
  1964. FModel.Cell[FModel.CursorY, FModel.CursorX] := Cell(FLastGraphicCharacter, FAttribute)
  1965. else
  1966. FModel.Cell[FModel.CursorY, FModel.CursorX - 1] := Cell(FLastGraphicCharacter, FAttribute);
  1967. end
  1968. else
  1969. begin
  1970. { type a new character }
  1971. if FNextCharacterWrapsToNextLine then
  1972. begin
  1973. FNextCharacterWrapsToNextLine := False;
  1974. if FModel.CursorY >= FScrollingRegionBottom then
  1975. begin
  1976. ScrollUp;
  1977. FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
  1978. end
  1979. else
  1980. FModel.SetCursorPos(CursorHomeX, FModel.CursorY + 1);
  1981. end;
  1982. if tmfInsertMode in FModeFlags then
  1983. for X := FModel.Width - 1 downto FModel.CursorX + 1 do
  1984. FModel.Cell[FModel.CursorY, X] := FModel.Cell[FModel.CursorY, X - 1];
  1985. FModel.Cell[FModel.CursorY, FModel.CursorX] := Cell(FLastGraphicCharacter, FAttribute);
  1986. if FModel.CursorX >= (FModel.Width - 1) then
  1987. begin
  1988. if tmfAutoWrapMode in FModeFlags then
  1989. FNextCharacterWrapsToNextLine := True;
  1990. end
  1991. else
  1992. FModel.SetCursorPos(FModel.CursorX + 1, FModel.CursorY);
  1993. end;
  1994. end;
  1995. procedure TTerminalController.WriteVT100CharFromCharset(Ch: Char;
  1996. Charset: TDecCharacterSet);
  1997. begin
  1998. Ch := Chr(Ord(Ch) and $7F);
  1999. if (Ch = #127) and not (Charset in CharacterSets96) then
  2000. exit;
  2001. case Charset of
  2002. dcsUSASCII:
  2003. WriteUTF32Char(Ord(Ch));
  2004. dcsBritishNRCS:
  2005. if Ch = '#' then
  2006. WriteUTF32Char($00A3)
  2007. else
  2008. WriteUTF32Char(Ord(Ch));
  2009. dcsFinnishNRCS:
  2010. case Ch of
  2011. #$5B:
  2012. WriteUTF32Char($00C4);
  2013. #$5C:
  2014. WriteUTF32Char($00D6);
  2015. #$5D:
  2016. WriteUTF32Char($00C5);
  2017. #$5E:
  2018. WriteUTF32Char($00DC);
  2019. #$60:
  2020. WriteUTF32Char($00E9);
  2021. #$7B:
  2022. WriteUTF32Char($00E4);
  2023. #$7C:
  2024. WriteUTF32Char($00F6);
  2025. #$7D:
  2026. WriteUTF32Char($00E5);
  2027. #$7E:
  2028. WriteUTF32Char($00FC);
  2029. else
  2030. WriteUTF32Char(Ord(Ch));
  2031. end;
  2032. dcsSwedishNRCS:
  2033. case Ch of
  2034. #$40:
  2035. WriteUTF32Char($00C9);
  2036. #$5B:
  2037. WriteUTF32Char($00C4);
  2038. #$5C:
  2039. WriteUTF32Char($00D6);
  2040. #$5D:
  2041. WriteUTF32Char($00C5);
  2042. #$5E:
  2043. WriteUTF32Char($00DC);
  2044. #$60:
  2045. WriteUTF32Char($00E9);
  2046. #$7B:
  2047. WriteUTF32Char($00E4);
  2048. #$7C:
  2049. WriteUTF32Char($00F6);
  2050. #$7D:
  2051. WriteUTF32Char($00E5);
  2052. #$7E:
  2053. WriteUTF32Char($00FC);
  2054. else
  2055. WriteUTF32Char(Ord(Ch));
  2056. end;
  2057. dcsGermanNRCS:
  2058. case Ch of
  2059. #$40:
  2060. WriteUTF32Char($00A7);
  2061. #$5B:
  2062. WriteUTF32Char($00C4);
  2063. #$5C:
  2064. WriteUTF32Char($00D6);
  2065. #$5D:
  2066. WriteUTF32Char($00DC);
  2067. #$7B:
  2068. WriteUTF32Char($00E4);
  2069. #$7C:
  2070. WriteUTF32Char($00F6);
  2071. #$7D:
  2072. WriteUTF32Char($00FC);
  2073. #$7E:
  2074. WriteUTF32Char($00DF);
  2075. else
  2076. WriteUTF32Char(Ord(Ch));
  2077. end;
  2078. dcsFrenchCanadianNRCS:
  2079. case Ch of
  2080. #$40:
  2081. WriteUTF32Char($00E0);
  2082. #$5B:
  2083. WriteUTF32Char($00E2);
  2084. #$5C:
  2085. WriteUTF32Char($00E7);
  2086. #$5D:
  2087. WriteUTF32Char($00EA);
  2088. #$5E:
  2089. WriteUTF32Char($00EE);
  2090. #$60:
  2091. WriteUTF32Char($00F4);
  2092. #$7B:
  2093. WriteUTF32Char($00E9);
  2094. #$7C:
  2095. WriteUTF32Char($00F9);
  2096. #$7D:
  2097. WriteUTF32Char($00E8);
  2098. #$7E:
  2099. WriteUTF32Char($00FB);
  2100. else
  2101. WriteUTF32Char(Ord(Ch));
  2102. end;
  2103. dcsFrenchNRCS:
  2104. case Ch of
  2105. #$23:
  2106. WriteUTF32Char($00A3);
  2107. #$40:
  2108. WriteUTF32Char($00E0);
  2109. #$5B:
  2110. WriteUTF32Char($00B0);
  2111. #$5C:
  2112. WriteUTF32Char($00E7);
  2113. #$5D:
  2114. WriteUTF32Char($00A7);
  2115. #$7B:
  2116. WriteUTF32Char($00E9);
  2117. #$7C:
  2118. WriteUTF32Char($00F9);
  2119. #$7D:
  2120. WriteUTF32Char($00E8);
  2121. #$7E:
  2122. WriteUTF32Char($00A8);
  2123. else
  2124. WriteUTF32Char(Ord(Ch));
  2125. end;
  2126. dcsItalianNRCS:
  2127. case Ch of
  2128. #$23:
  2129. WriteUTF32Char($00A3);
  2130. #$40:
  2131. WriteUTF32Char($00A7);
  2132. #$5B:
  2133. WriteUTF32Char($00B0);
  2134. #$5C:
  2135. WriteUTF32Char($00E7);
  2136. #$5D:
  2137. WriteUTF32Char($00E9);
  2138. #$60:
  2139. WriteUTF32Char($00F9);
  2140. #$7B:
  2141. WriteUTF32Char($00E0);
  2142. #$7C:
  2143. WriteUTF32Char($00F2);
  2144. #$7D:
  2145. WriteUTF32Char($00E8);
  2146. #$7E:
  2147. WriteUTF32Char($00EC);
  2148. else
  2149. WriteUTF32Char(Ord(Ch));
  2150. end;
  2151. dcsSpanishNRCS:
  2152. case Ch of
  2153. #$23:
  2154. WriteUTF32Char($00A3);
  2155. #$40:
  2156. WriteUTF32Char($00A7);
  2157. #$5B:
  2158. WriteUTF32Char($00A1);
  2159. #$5C:
  2160. WriteUTF32Char($00D1);
  2161. #$5D:
  2162. WriteUTF32Char($00BF);
  2163. #$7B:
  2164. WriteUTF32Char($00B0);
  2165. #$7C:
  2166. WriteUTF32Char($00F1);
  2167. #$7D:
  2168. WriteUTF32Char($00E7);
  2169. else
  2170. WriteUTF32Char(Ord(Ch));
  2171. end;
  2172. dcsDutchNRCS:
  2173. case Ch of
  2174. #$23:
  2175. WriteUTF32Char($00A3);
  2176. #$40:
  2177. WriteUTF32Char($00BE);
  2178. #$5B:
  2179. WriteUTF32Char($0133);
  2180. #$5C:
  2181. WriteUTF32Char($00BD);
  2182. #$5D:
  2183. WriteUTF32Char($007C);
  2184. #$7B:
  2185. WriteUTF32Char($00A8);
  2186. #$7C:
  2187. WriteUTF32Char($0192);
  2188. #$7D:
  2189. WriteUTF32Char($00BC);
  2190. #$7E:
  2191. WriteUTF32Char($00B4);
  2192. else
  2193. WriteUTF32Char(Ord(Ch));
  2194. end;
  2195. dcsSwissNRCS:
  2196. case Ch of
  2197. #$23:
  2198. WriteUTF32Char($00F9);
  2199. #$40:
  2200. WriteUTF32Char($00E0);
  2201. #$5B:
  2202. WriteUTF32Char($00E9);
  2203. #$5C:
  2204. WriteUTF32Char($00E7);
  2205. #$5D:
  2206. WriteUTF32Char($00EA);
  2207. #$5E:
  2208. WriteUTF32Char($00EE);
  2209. #$5F:
  2210. WriteUTF32Char($00E8);
  2211. #$60:
  2212. WriteUTF32Char($00F4);
  2213. #$7B:
  2214. WriteUTF32Char($00E4);
  2215. #$7C:
  2216. WriteUTF32Char($00F6);
  2217. #$7D:
  2218. WriteUTF32Char($00FC);
  2219. #$7E:
  2220. WriteUTF32Char($00FB);
  2221. else
  2222. WriteUTF32Char(Ord(Ch));
  2223. end;
  2224. dcsNorwegianDanishNRCS:
  2225. case Ch of
  2226. #$40:
  2227. WriteUTF32Char($00C4);
  2228. #$5B:
  2229. WriteUTF32Char($00C6);
  2230. #$5C:
  2231. WriteUTF32Char($00D8);
  2232. #$5D:
  2233. WriteUTF32Char($00C5);
  2234. #$5E:
  2235. WriteUTF32Char($00DC);
  2236. #$60:
  2237. WriteUTF32Char($00E4);
  2238. #$7B:
  2239. WriteUTF32Char($00E6);
  2240. #$7C:
  2241. WriteUTF32Char($00F8);
  2242. #$7D:
  2243. WriteUTF32Char($00E5);
  2244. #$7E:
  2245. WriteUTF32Char($00FC);
  2246. else
  2247. WriteUTF32Char(Ord(Ch));
  2248. end;
  2249. dcsPortugueseNRCS:
  2250. case Ch of
  2251. #$5B:
  2252. WriteUTF32Char($00C3);
  2253. #$5C:
  2254. WriteUTF32Char($00C7);
  2255. #$5D:
  2256. WriteUTF32Char($00D5);
  2257. #$7B:
  2258. WriteUTF32Char($00E3);
  2259. #$7C:
  2260. WriteUTF32Char($00E7);
  2261. #$7D:
  2262. WriteUTF32Char($00F5);
  2263. else
  2264. WriteUTF32Char(Ord(Ch));
  2265. end;
  2266. dcsGreekNRCS:
  2267. case Ch of
  2268. 'n':
  2269. WriteUTF32Char($03A7);
  2270. 'v':
  2271. WriteUTF32Char($039E);
  2272. 'a'..'m', 'o'..'q':
  2273. WriteUTF32Char(Ord(Ch) + ($0391 - Ord('a')));
  2274. 'r'..'u', 'w'..'x':
  2275. WriteUTF32Char(Ord(Ch) + ($0392 - Ord('a')));
  2276. 'y'..'z':
  2277. WriteUTF32Char($0020);
  2278. else
  2279. WriteUTF32Char(Ord(Ch));
  2280. end;
  2281. dcsTurkishNRCS:
  2282. case Ch of
  2283. '&':
  2284. WriteUTF32Char($011F);
  2285. #$40:
  2286. WriteUTF32Char($0130);
  2287. #$5B:
  2288. WriteUTF32Char($015E);
  2289. #$5C:
  2290. WriteUTF32Char($00D6);
  2291. #$5D:
  2292. WriteUTF32Char($00C7);
  2293. #$5E:
  2294. WriteUTF32Char($00DC);
  2295. #$60:
  2296. WriteUTF32Char($011E);
  2297. #$7B:
  2298. WriteUTF32Char($015F);
  2299. #$7C:
  2300. WriteUTF32Char($00F6);
  2301. #$7D:
  2302. WriteUTF32Char($00E7);
  2303. #$7E:
  2304. WriteUTF32Char($00FC);
  2305. else
  2306. WriteUTF32Char(Ord(Ch));
  2307. end;
  2308. dcsHebrewNRCS:
  2309. case Ch of
  2310. #$60..#$7A:
  2311. WriteUTF32Char(Ord(Ch) + ($05D0 - $60));
  2312. else
  2313. WriteUTF32Char(Ord(Ch));
  2314. end;
  2315. dcsDecHebrew:
  2316. case Ch of
  2317. '!'..'''', ')', '+'..'9', ';'..'?':
  2318. WriteVT100CharFromCharset(Ch, dcsDecSupplemental);
  2319. '(':
  2320. WriteUTF32Char($00A8);
  2321. '*':
  2322. WriteUTF32Char($00D7);
  2323. ':':
  2324. WriteUTF32Char($00F7);
  2325. #$60..#$7A:
  2326. WriteUTF32Char(Ord(Ch) + ($05D0 - $60));
  2327. '@'..'_', '{'..'~':
  2328. WriteUTF32Char($FFFD);
  2329. else
  2330. WriteUTF32Char(Ord(Ch));
  2331. end;
  2332. dcsDecGreek:
  2333. case Ch of
  2334. '!'..'?':
  2335. WriteVT100CharFromCharset(Ch, dcsDecSupplemental);
  2336. '@':
  2337. WriteUTF32Char($03CA);
  2338. 'A'..'O':
  2339. WriteUTF32Char(Ord(Ch) + ($0391 - Ord('A')));
  2340. 'P':
  2341. WriteUTF32Char($FFFD);
  2342. 'Q'..'R':
  2343. WriteUTF32Char(Ord(Ch) + ($03A0 - Ord('Q')));
  2344. 'S'..'Y':
  2345. WriteUTF32Char(Ord(Ch) + ($03A3 - Ord('S')));
  2346. 'Z'..']':
  2347. WriteUTF32Char(Ord(Ch) + ($03AC - Ord('Z')));
  2348. '^':
  2349. WriteUTF32Char($FFFD);
  2350. '_':
  2351. WriteUTF32Char($03CC);
  2352. '`':
  2353. WriteUTF32Char($03CB);
  2354. 'a'..'o':
  2355. WriteUTF32Char(Ord(Ch) + ($03B1 - Ord('a')));
  2356. 'p':
  2357. WriteUTF32Char($FFFD);
  2358. 'q'..'r':
  2359. WriteUTF32Char(Ord(Ch) + ($03C0 - Ord('q')));
  2360. 's'..'y':
  2361. WriteUTF32Char(Ord(Ch) + ($03C3 - Ord('s')));
  2362. 'z':
  2363. WriteUTF32Char($03C2);
  2364. '{':
  2365. WriteUTF32Char($03CD);
  2366. '|':
  2367. WriteUTF32Char($03CE);
  2368. '}':
  2369. WriteUTF32Char($0384);
  2370. '~':
  2371. WriteUTF32Char($FFFD);
  2372. else
  2373. WriteUTF32Char(Ord(Ch));
  2374. end;
  2375. dcsDecTurkish:
  2376. case Ch of
  2377. '(':
  2378. WriteUTF32Char($00A8);
  2379. '.':
  2380. WriteUTF32Char($0130);
  2381. '>':
  2382. WriteUTF32Char($0131);
  2383. 'P':
  2384. WriteUTF32Char($011E);
  2385. '^':
  2386. WriteUTF32Char($015E);
  2387. 'p':
  2388. WriteUTF32Char($011F);
  2389. '~':
  2390. WriteUTF32Char($015F);
  2391. else
  2392. WriteVT100CharFromCharset(Ch, dcsDecSupplemental);
  2393. end;
  2394. dcsDecCyrillic:
  2395. if (Ch >= Low(DecCyrillicCharacterSet)) and (Ch <= High(DecCyrillicCharacterSet)) then
  2396. WriteUTF32Char(DecCyrillicCharacterSet[Ch])
  2397. else
  2398. WriteUTF32Char($FFFD);
  2399. dcsDecSpecialGraphics:
  2400. if (Ch >= Low(DecSpecialGraphicsCharacterSet)) and (Ch <= High(DecSpecialGraphicsCharacterSet)) then
  2401. WriteUTF32Char(DecSpecialGraphicsCharacterSet[Ch])
  2402. else
  2403. WriteUTF32Char(Ord(Ch));
  2404. dcsDecTechnical:
  2405. if (Ch >= Low(DecTechnicalCharacterSet)) and (Ch <= High(DecTechnicalCharacterSet)) then
  2406. WriteUTF32Char(DecTechnicalCharacterSet[Ch])
  2407. else
  2408. WriteUTF32Char(Ord(Ch));
  2409. dcsDecSupplemental:
  2410. case Ch of
  2411. Chr($A8 - $80):
  2412. WriteUTF32Char($00A4);
  2413. Chr($D7 - $80):
  2414. WriteUTF32Char($0152);
  2415. Chr($DD - $80):
  2416. WriteUTF32Char($0178);
  2417. Chr($F7 - $80):
  2418. WriteUTF32Char($0153);
  2419. Chr($FD - $80):
  2420. WriteUTF32Char($00FF);
  2421. Chr($A4 - $80),
  2422. Chr($A6 - $80),
  2423. Chr($AC - $80)..Chr($AF - $80),
  2424. Chr($B4 - $80),
  2425. Chr($B8 - $80),
  2426. Chr($BE - $80),
  2427. Chr($D0 - $80),
  2428. Chr($DE - $80),
  2429. Chr($F0 - $80),
  2430. Chr($FE - $80):
  2431. { REPLACEMENT CHARACTER }
  2432. WriteUTF32Char($FFFD);
  2433. #0..#32,#127:
  2434. WriteUTF32Char(Ord(Ch));
  2435. else
  2436. WriteUTF32Char(Ord(Ch) + $80);
  2437. end;
  2438. dcsISOLatin1Supplemental:
  2439. WriteUTF32Char(Ord(Ch) + $80);
  2440. end;
  2441. end;
  2442. procedure TTerminalController.WriteVT100Char(Ch: Char);
  2443. begin
  2444. if Ord(Ch) <= 127 then
  2445. WriteVT100CharFromCharset(Ch, FGCharacterSets[FGLCharacterSet])
  2446. else
  2447. WriteVT100CharFromCharset(Ch, FGCharacterSets[FGRCharacterSet]);
  2448. end;
  2449. procedure TTerminalController.WriteVT52Char(Ch: Char);
  2450. begin
  2451. Ch := Chr(Ord(Ch) and 127);
  2452. case FVT52CharacterSet of
  2453. v52csASCII:
  2454. WriteUTF32Char(Ord(Ch));
  2455. v52csGraphics:
  2456. if (Ch >= Low(VT52GraphicsCharacterSet)) and (Ch <= High(VT52GraphicsCharacterSet)) then
  2457. WriteUTF32Char(VT52GraphicsCharacterSet[Ch])
  2458. else
  2459. WriteUTF32Char(Ord(Ch));
  2460. end;
  2461. end;
  2462. procedure TTerminalController.WriteRepeatedCharacter(const EGC: TExtendedGraphemeCluster; Count: Integer);
  2463. var
  2464. I, J: Integer;
  2465. begin
  2466. for I := 1 to Count do
  2467. begin
  2468. J := 1;
  2469. while J <= Length(EGC) do
  2470. begin
  2471. if (EGC[J] >= #$D800) and (EGC[J] <= #$DFFF) then
  2472. begin
  2473. if (EGC[J] < #$DC00) and (J < Length(EGC)) and (EGC[J + 1] >= #$DC00) and (EGC[J + 1] <= #$DFFF) then
  2474. begin
  2475. WriteUTF32Char($10000 + ((LongWord(EGC[J]) - $D800) shl 10) + (LongWord(EGC[J + 1]) - $DC00));
  2476. Inc(J, 2);
  2477. end
  2478. else
  2479. { invalid UTF-16 code unit, skip it }
  2480. Inc(J);
  2481. end
  2482. else
  2483. WriteUTF32Char(LongWord(EGC[J]));
  2484. Inc(J);
  2485. end;
  2486. end;
  2487. end;
  2488. procedure TTerminalController.HandleC1(Ch: TC1Char);
  2489. begin
  2490. case Ch of
  2491. C1_CSI:
  2492. begin
  2493. FState := tsmsCSI;
  2494. ClearControlSequence;
  2495. end;
  2496. C1_OSC:
  2497. begin
  2498. FState := tsmsOSC;
  2499. FOperatingSystemCommand := '';
  2500. end;
  2501. C1_DCS:
  2502. begin
  2503. FState := tsmsDCS;
  2504. FDeviceControlString := '';
  2505. end;
  2506. C1_RI:
  2507. begin
  2508. FNextCharacterWrapsToNextLine := False;
  2509. FState := tsmsInitial;
  2510. if FModel.CursorY = 0 then
  2511. begin
  2512. ScrollDown;
  2513. FModel.SetCursorPos(FModel.CursorX, FModel.CursorY);
  2514. end
  2515. else
  2516. FModel.SetCursorPos(FModel.CursorX, FModel.CursorY - 1);
  2517. end;
  2518. C1_IND:
  2519. begin
  2520. FNextCharacterWrapsToNextLine := False;
  2521. FState := tsmsInitial;
  2522. if FModel.CursorY >= FScrollingRegionBottom then
  2523. begin
  2524. ScrollUp;
  2525. FModel.SetCursorPos(FModel.CursorX, FModel.CursorY);
  2526. end
  2527. else
  2528. FModel.SetCursorPos(FModel.CursorX, FModel.CursorY + 1);
  2529. end;
  2530. C1_NEL:
  2531. begin
  2532. FNextCharacterWrapsToNextLine := False;
  2533. FState := tsmsInitial;
  2534. if FModel.CursorY >= FScrollingRegionBottom then
  2535. begin
  2536. ScrollUp;
  2537. FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
  2538. end
  2539. else
  2540. FModel.SetCursorPos(CursorHomeX, FModel.CursorY + 1);
  2541. end;
  2542. C1_HTS:
  2543. begin
  2544. FState := tsmsInitial;
  2545. FTabStops[FModel.CursorX] := True;
  2546. end
  2547. else
  2548. { error }
  2549. FLogger.LogMessage(vlWarning, 'Unhandled C1 character: #' + IntToStr(Ord(Ch)));
  2550. FState := tsmsInitial;
  2551. end;
  2552. end;
  2553. procedure TTerminalController.HandleENQ;
  2554. begin
  2555. TransmitStr(VT100AnswerbackString);
  2556. end;
  2557. procedure TTerminalController.HandleCR;
  2558. begin
  2559. FNextCharacterWrapsToNextLine := False;
  2560. FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
  2561. end;
  2562. procedure TTerminalController.HandleLF;
  2563. begin
  2564. FNextCharacterWrapsToNextLine := False;
  2565. if FModel.CursorY >= FScrollingRegionBottom then
  2566. begin
  2567. ScrollUp;
  2568. FModel.SetCursorPos(FModel.CursorX, FModel.CursorY);
  2569. end
  2570. else
  2571. FModel.SetCursorPos(FModel.CursorX, FModel.CursorY + 1);
  2572. if tmfAutoNewLine in ModeFlags then
  2573. FModel.SetCursorPos(CursorHomeX, FModel.CursorY);
  2574. end;
  2575. procedure TTerminalController.HandleBS;
  2576. begin
  2577. FNextCharacterWrapsToNextLine := False;
  2578. if FModel.CursorX > 0 then
  2579. FModel.SetCursorPos(FModel.CursorX - 1, FModel.CursorY);
  2580. end;
  2581. procedure TTerminalController.HandleHT;
  2582. begin
  2583. CursorForwardTabulation(1);
  2584. end;
  2585. procedure TTerminalController.CursorForwardTabulation(TabStops: Integer);
  2586. var
  2587. CX: Integer;
  2588. begin
  2589. if TabStops < 0 then
  2590. exit;
  2591. if TabStops = 0 then
  2592. TabStops := 1;
  2593. CX := FModel.CursorX;
  2594. while (TabStops > 0) and (CX < (FModel.Width - 1)) do
  2595. begin
  2596. Dec(TabStops);
  2597. repeat
  2598. if CX < (FModel.Width - 1) then
  2599. Inc(CX);
  2600. until FTabStops[CX] or (CX >= (FModel.Width - 1));
  2601. end;
  2602. FModel.SetCursorPos(CX, FModel.CursorY);
  2603. end;
  2604. procedure TTerminalController.CursorBackwardTabulation(TabStops: Integer);
  2605. var
  2606. CX: Integer;
  2607. begin
  2608. if TabStops < 0 then
  2609. exit;
  2610. if TabStops = 0 then
  2611. TabStops := 1;
  2612. CX := FModel.CursorX;
  2613. while (TabStops > 0) and (CX > 0) do
  2614. begin
  2615. Dec(TabStops);
  2616. repeat
  2617. if CX > 0 then
  2618. Dec(CX);
  2619. until FTabStops[CX] or (CX = 0);
  2620. end;
  2621. FModel.SetCursorPos(CX, FModel.CursorY);
  2622. end;
  2623. procedure TTerminalController.EnterVT52Mode;
  2624. begin
  2625. FVT52CharacterSet := v52csASCII;
  2626. FDecConformanceLevel := dclVT52;
  2627. FState := tsmsVT52_Initial;
  2628. end;
  2629. procedure TTerminalController.LeaveVT52Mode;
  2630. begin
  2631. FDecConformanceLevel := dclVT100;
  2632. Exclude(FModeFlags, tmfSend8BitC1Controls);
  2633. FState := tsmsInitial;
  2634. end;
  2635. procedure TTerminalController.TransmitData(const buf; Bytes: SizeUInt);
  2636. begin
  2637. if Assigned(FOnTransmitData) then
  2638. FOnTransmitData(buf, Bytes);
  2639. end;
  2640. procedure TTerminalController.TransmitStr(const S: string);
  2641. begin
  2642. TransmitData(s[1], Length(S));
  2643. end;
  2644. procedure TTerminalController.HardReset;
  2645. begin
  2646. FDecConformanceLevel := MaxConformanceLevelForTerminal[FTerminalType];
  2647. FAttribute := DefaultAttribute;
  2648. FModeFlags := DefaultModeFlags;
  2649. FSavedCursor.Reset;
  2650. FTabStops.Reset;
  2651. { todo: what are the default character sets? }
  2652. FDesignatingCharacterSet := gcsG0;
  2653. FGLCharacterSet := gcsG0;
  2654. FGRCharacterSet := gcsG1;
  2655. FGCharacterSets[gcsG0] := dcsUSASCII;
  2656. FGCharacterSets[gcsG1] := dcsUSASCII;
  2657. FGCharacterSets[gcsG2] := dcsUSASCII;
  2658. FGCharacterSets[gcsG3] := dcsUSASCII;
  2659. FVT52CharacterSet := v52csASCII;
  2660. FOldMouseX := 0;
  2661. FOldMouseY := 0;
  2662. FOldMouseButtons := [];
  2663. FMouseTrackingMode := tmtmNone;
  2664. FMouseProtocolEncoding := tmpeX10;
  2665. FScrollingRegionTop := 0;
  2666. FScrollingRegionBottom := FModel.Height - 1;
  2667. FScrollingRegionLeft := 0;
  2668. FScrollingRegionRight := FModel.Width - 1;
  2669. if FDecConformanceLevel = dclVT52 then
  2670. FState := tsmsVT52_Initial
  2671. else
  2672. FState := tsmsInitial;
  2673. FUTF8_Build := 0;
  2674. ClearControlSequence;
  2675. FOperatingSystemCommand := '';
  2676. FDeviceControlString := '';
  2677. FVT100AnswerbackString := '';
  2678. FLastGraphicCharacter := '';
  2679. FNextCharacterWrapsToNextLine := False;
  2680. FModel.Reset;
  2681. end;
  2682. procedure TTerminalController.SoftReset;
  2683. begin
  2684. FLogger.LogMessage(vlWarning, 'Soft reset not yet implemented');
  2685. end;
  2686. constructor TTerminalController.Create(AModel: TTerminalModel;
  2687. ATerminalType: TTerminalType);
  2688. begin
  2689. FTerminalType := ATerminalType;
  2690. FSavedCursor := TTerminalSavedCursor.Create;
  2691. FLogger := TFileLogger.Create('fpterm.log', DefaultLogLevel);
  2692. FModel := AModel;
  2693. FTabStops := TTerminalTabStops.Create;
  2694. HardReset;
  2695. end;
  2696. destructor TTerminalController.Destroy;
  2697. begin
  2698. FreeAndNil(FSavedCursor);
  2699. FreeAndNil(FTabStops);
  2700. FreeAndNil(FLogger);
  2701. inherited Destroy;
  2702. end;
  2703. function TTerminalController.Resize(NewWidth, NewHeight: Integer): Boolean;
  2704. var
  2705. OldWidth, OldHeight: Integer;
  2706. begin
  2707. OldWidth := FModel.Width;
  2708. OldHeight := FModel.Height;
  2709. if FModel.Resize(NewWidth, NewHeight) then
  2710. begin
  2711. Result := True;
  2712. if FScrollingRegionBottom = (OldHeight - 1) then
  2713. FScrollingRegionBottom := NewHeight - 1
  2714. else if FScrollingRegionBottom > (NewHeight - 1) then
  2715. FScrollingRegionBottom := NewHeight - 1;
  2716. if FScrollingRegionTop > FScrollingRegionBottom then
  2717. FScrollingRegionTop := FScrollingRegionBottom;
  2718. if FScrollingRegionRight = (OldWidth - 1) then
  2719. FScrollingRegionRight := NewWidth - 1
  2720. else if FScrollingRegionRight > (NewWidth - 1) then
  2721. FScrollingRegionRight := NewWidth - 1;
  2722. if FScrollingRegionLeft > FScrollingRegionRight then
  2723. FScrollingRegionLeft := FScrollingRegionRight;
  2724. if Assigned(FOnResize) then
  2725. FOnResize(NewWidth, NewHeight);
  2726. end
  2727. else
  2728. Result := False;
  2729. end;
  2730. procedure TTerminalController.ReceiveData(const buf; Bytes: SizeUInt);
  2731. var
  2732. I: SizeUInt;
  2733. Ch: Char;
  2734. Y, X: Integer;
  2735. begin
  2736. if Bytes <= 0 then
  2737. exit;
  2738. for I := 0 to Bytes - 1 do
  2739. begin
  2740. Ch := PChar(@buf)[I];
  2741. case FState of
  2742. tsmsInitial:
  2743. begin
  2744. case Ch of
  2745. C0_ENQ:
  2746. HandleENQ;
  2747. C0_CR:
  2748. HandleCR;
  2749. C0_VT,
  2750. C0_FF,
  2751. C0_LF:
  2752. HandleLF;
  2753. C0_BS:
  2754. HandleBS;
  2755. C0_HT:
  2756. HandleHT;
  2757. C0_ESC:
  2758. FState := tsmsESC;
  2759. C0_SI:
  2760. FGLCharacterSet := gcsG0;
  2761. C0_SO:
  2762. FGLCharacterSet := gcsG1;
  2763. #32..#127:
  2764. WriteVT100Char(Ch);
  2765. #$80..#$9F:
  2766. HandleC1(Ch);
  2767. #$A0..#$FF:
  2768. begin
  2769. if tmfUTF8Mode in ModeFlags then
  2770. begin
  2771. case Ch of
  2772. #%11000000..#%11011111:
  2773. begin
  2774. FState := tsmsUTF8_1ByteLeft;
  2775. FUTF8_Build := Ord(Ch) and %11111;
  2776. end;
  2777. #%11100000..#%11101111:
  2778. begin
  2779. FState := tsmsUTF8_2BytesLeft;
  2780. FUTF8_Build := Ord(Ch) and %1111;
  2781. end;
  2782. #%11110000..#%11110111:
  2783. begin
  2784. FState := tsmsUTF8_3BytesLeft;
  2785. FUTF8_Build := Ord(Ch) and %111;
  2786. end;
  2787. else
  2788. FLogger.LogMessage(vlWarning, 'Unhandled character: #' + IntToStr(Ord(Ch)));
  2789. end;
  2790. end
  2791. else
  2792. WriteVT100Char(Ch);
  2793. end;
  2794. else
  2795. FLogger.LogMessage(vlWarning, 'Unhandled character: #' + IntToStr(Ord(Ch)));
  2796. end;
  2797. end;
  2798. tsmsESC:
  2799. begin
  2800. case Ch of
  2801. #27:
  2802. FState := tsmsESC;
  2803. #$40..#$5F:
  2804. HandleC1(Chr(Ord(Ch) + $40));
  2805. ' ':
  2806. FState := tsmsESC_SP;
  2807. '#':
  2808. FState := tsmsESC_Hash;
  2809. '%':
  2810. FState := tsmsESC_Percent;
  2811. '(':
  2812. begin
  2813. FState := tsmsDesignateG0123CharacterSet94;
  2814. FDesignatingCharacterSet := gcsG0;
  2815. end;
  2816. ')':
  2817. begin
  2818. FState := tsmsDesignateG0123CharacterSet94;
  2819. FDesignatingCharacterSet := gcsG1;
  2820. end;
  2821. '*':
  2822. begin
  2823. FState := tsmsDesignateG0123CharacterSet94;
  2824. FDesignatingCharacterSet := gcsG2;
  2825. end;
  2826. '+':
  2827. begin
  2828. FState := tsmsDesignateG0123CharacterSet94;
  2829. FDesignatingCharacterSet := gcsG3;
  2830. end;
  2831. '-':
  2832. begin
  2833. FState := tsmsDesignateG0123CharacterSet96;
  2834. FDesignatingCharacterSet := gcsG1;
  2835. end;
  2836. '.':
  2837. begin
  2838. FState := tsmsDesignateG0123CharacterSet96;
  2839. FDesignatingCharacterSet := gcsG2;
  2840. end;
  2841. '/':
  2842. begin
  2843. FState := tsmsDesignateG0123CharacterSet96;
  2844. FDesignatingCharacterSet := gcsG3;
  2845. end;
  2846. '7':
  2847. begin
  2848. SaveCursor;
  2849. FState := tsmsInitial;
  2850. end;
  2851. '8':
  2852. begin
  2853. RestoreCursor;
  2854. FState := tsmsInitial;
  2855. end;
  2856. 'c':
  2857. HardReset;
  2858. 'n':
  2859. FGLCharacterSet := gcsG2;
  2860. 'o':
  2861. FGLCharacterSet := gcsG3;
  2862. '|':
  2863. FGRCharacterSet := gcsG3;
  2864. '}':
  2865. FGRCharacterSet := gcsG2;
  2866. '~':
  2867. FGRCharacterSet := gcsG1;
  2868. else
  2869. begin
  2870. { error }
  2871. FLogger.LogMessage(vlWarning, 'Unhandled ESC sequence character: #' + IntToStr(Ord(Ch)));
  2872. FState := tsmsInitial;
  2873. end;
  2874. end;
  2875. end;
  2876. tsmsDesignateG0123CharacterSet94:
  2877. begin
  2878. case Ch of
  2879. 'A':
  2880. begin
  2881. FGCharacterSets[FDesignatingCharacterSet] := dcsBritishNRCS;
  2882. FState := tsmsInitial;
  2883. FDesignatingCharacterSet := gcsG0;
  2884. end;
  2885. 'B':
  2886. begin
  2887. FGCharacterSets[FDesignatingCharacterSet] := dcsUSASCII;
  2888. FState := tsmsInitial;
  2889. FDesignatingCharacterSet := gcsG0;
  2890. end;
  2891. 'C', '5':
  2892. begin
  2893. if FDecConformanceLevel >= dclVT200 then
  2894. FGCharacterSets[FDesignatingCharacterSet] := dcsFinnishNRCS;
  2895. FState := tsmsInitial;
  2896. FDesignatingCharacterSet := gcsG0;
  2897. end;
  2898. 'H', '7':
  2899. begin
  2900. if FDecConformanceLevel >= dclVT200 then
  2901. FGCharacterSets[FDesignatingCharacterSet] := dcsSwedishNRCS;
  2902. FState := tsmsInitial;
  2903. FDesignatingCharacterSet := gcsG0;
  2904. end;
  2905. 'K':
  2906. begin
  2907. if FDecConformanceLevel >= dclVT200 then
  2908. FGCharacterSets[FDesignatingCharacterSet] := dcsGermanNRCS;
  2909. FState := tsmsInitial;
  2910. FDesignatingCharacterSet := gcsG0;
  2911. end;
  2912. 'Q', '9':
  2913. begin
  2914. if FDecConformanceLevel >= dclVT200 then
  2915. FGCharacterSets[FDesignatingCharacterSet] := dcsFrenchCanadianNRCS;
  2916. FState := tsmsInitial;
  2917. FDesignatingCharacterSet := gcsG0;
  2918. end;
  2919. 'R', 'f':
  2920. begin
  2921. if FDecConformanceLevel >= dclVT200 then
  2922. FGCharacterSets[FDesignatingCharacterSet] := dcsFrenchNRCS;
  2923. FState := tsmsInitial;
  2924. FDesignatingCharacterSet := gcsG0;
  2925. end;
  2926. 'Y':
  2927. begin
  2928. if FDecConformanceLevel >= dclVT200 then
  2929. FGCharacterSets[FDesignatingCharacterSet] := dcsItalianNRCS;
  2930. FState := tsmsInitial;
  2931. FDesignatingCharacterSet := gcsG0;
  2932. end;
  2933. 'Z':
  2934. begin
  2935. if FDecConformanceLevel >= dclVT200 then
  2936. FGCharacterSets[FDesignatingCharacterSet] := dcsSpanishNRCS;
  2937. FState := tsmsInitial;
  2938. FDesignatingCharacterSet := gcsG0;
  2939. end;
  2940. '4':
  2941. begin
  2942. if FDecConformanceLevel >= dclVT200 then
  2943. FGCharacterSets[FDesignatingCharacterSet] := dcsDutchNRCS;
  2944. FState := tsmsInitial;
  2945. FDesignatingCharacterSet := gcsG0;
  2946. end;
  2947. '=':
  2948. begin
  2949. if FDecConformanceLevel >= dclVT200 then
  2950. FGCharacterSets[FDesignatingCharacterSet] := dcsSwissNRCS;
  2951. FState := tsmsInitial;
  2952. FDesignatingCharacterSet := gcsG0;
  2953. end;
  2954. '`', 'E', '6':
  2955. begin
  2956. if FDecConformanceLevel >= dclVT200 then
  2957. FGCharacterSets[FDesignatingCharacterSet] := dcsNorwegianDanishNRCS;
  2958. FState := tsmsInitial;
  2959. FDesignatingCharacterSet := gcsG0;
  2960. end;
  2961. '0':
  2962. begin
  2963. FGCharacterSets[FDesignatingCharacterSet] := dcsDecSpecialGraphics;
  2964. FState := tsmsInitial;
  2965. FDesignatingCharacterSet := gcsG0;
  2966. end;
  2967. '<':
  2968. begin
  2969. if FDecConformanceLevel >= dclVT200 then
  2970. FGCharacterSets[FDesignatingCharacterSet] := dcsDecSupplemental;
  2971. FState := tsmsInitial;
  2972. FDesignatingCharacterSet := gcsG0;
  2973. end;
  2974. '>':
  2975. begin
  2976. if FDecConformanceLevel >= dclVT300 then
  2977. FGCharacterSets[FDesignatingCharacterSet] := dcsDecTechnical;
  2978. FState := tsmsInitial;
  2979. FDesignatingCharacterSet := gcsG0;
  2980. end;
  2981. '%':
  2982. FState := tsmsDesignateG0123CharacterSet94_Percent;
  2983. '"':
  2984. FState := tsmsDesignateG0123CharacterSet94_Quote;
  2985. '&':
  2986. FState := tsmsDesignateG0123CharacterSet94_Ampersand;
  2987. #27:
  2988. begin
  2989. FState := tsmsESC;
  2990. FDesignatingCharacterSet := gcsG0;
  2991. end;
  2992. else
  2993. begin
  2994. FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' Character Set not implemented: ' + Ch);
  2995. FState := tsmsInitial;
  2996. FDesignatingCharacterSet := gcsG0;
  2997. end;
  2998. end;
  2999. end;
  3000. tsmsDesignateG0123CharacterSet94_Percent:
  3001. begin
  3002. case Ch of
  3003. '0':
  3004. begin
  3005. if FDecConformanceLevel >= dclVT500 then
  3006. FGCharacterSets[FDesignatingCharacterSet] := dcsDecTurkish;
  3007. FState := tsmsInitial;
  3008. FDesignatingCharacterSet := gcsG0;
  3009. end;
  3010. '2':
  3011. begin
  3012. if FDecConformanceLevel >= dclVT500 then
  3013. FGCharacterSets[FDesignatingCharacterSet] := dcsTurkishNRCS;
  3014. FState := tsmsInitial;
  3015. FDesignatingCharacterSet := gcsG0;
  3016. end;
  3017. '5':
  3018. begin
  3019. if FDecConformanceLevel >= dclVT300 then
  3020. FGCharacterSets[FDesignatingCharacterSet] := dcsDecSupplemental;
  3021. FState := tsmsInitial;
  3022. FDesignatingCharacterSet := gcsG0;
  3023. end;
  3024. '6':
  3025. begin
  3026. if FDecConformanceLevel >= dclVT300 then
  3027. FGCharacterSets[FDesignatingCharacterSet] := dcsPortugueseNRCS;
  3028. FState := tsmsInitial;
  3029. FDesignatingCharacterSet := gcsG0;
  3030. end;
  3031. '=':
  3032. begin
  3033. if FDecConformanceLevel >= dclVT500 then
  3034. FGCharacterSets[FDesignatingCharacterSet] := dcsHebrewNRCS;
  3035. FState := tsmsInitial;
  3036. FDesignatingCharacterSet := gcsG0;
  3037. end;
  3038. #27:
  3039. begin
  3040. FState := tsmsESC;
  3041. FDesignatingCharacterSet := gcsG0;
  3042. end;
  3043. else
  3044. begin
  3045. FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' Character Set not implemented: %' + Ch);
  3046. FState := tsmsInitial;
  3047. FDesignatingCharacterSet := gcsG0;
  3048. end;
  3049. end;
  3050. end;
  3051. tsmsDesignateG0123CharacterSet94_Quote:
  3052. begin
  3053. case Ch of
  3054. '>':
  3055. begin
  3056. if FDecConformanceLevel >= dclVT500 then
  3057. FGCharacterSets[FDesignatingCharacterSet] := dcsGreekNRCS;
  3058. FState := tsmsInitial;
  3059. FDesignatingCharacterSet := gcsG0;
  3060. end;
  3061. '4':
  3062. begin
  3063. if FDecConformanceLevel >= dclVT500 then
  3064. FGCharacterSets[FDesignatingCharacterSet] := dcsDecHebrew;
  3065. FState := tsmsInitial;
  3066. FDesignatingCharacterSet := gcsG0;
  3067. end;
  3068. '?':
  3069. begin
  3070. if FDecConformanceLevel >= dclVT500 then
  3071. FGCharacterSets[FDesignatingCharacterSet] := dcsDecGreek;
  3072. FState := tsmsInitial;
  3073. FDesignatingCharacterSet := gcsG0;
  3074. end;
  3075. #27:
  3076. begin
  3077. FState := tsmsESC;
  3078. FDesignatingCharacterSet := gcsG0;
  3079. end;
  3080. else
  3081. begin
  3082. FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' Character Set not implemented: "' + Ch);
  3083. FState := tsmsInitial;
  3084. FDesignatingCharacterSet := gcsG0;
  3085. end;
  3086. end;
  3087. end;
  3088. tsmsDesignateG0123CharacterSet94_Ampersand:
  3089. begin
  3090. case Ch of
  3091. '4':
  3092. begin
  3093. if FDecConformanceLevel >= dclVT500 then
  3094. FGCharacterSets[FDesignatingCharacterSet] := dcsDecCyrillic;
  3095. FState := tsmsInitial;
  3096. FDesignatingCharacterSet := gcsG0;
  3097. end;
  3098. #27:
  3099. begin
  3100. FState := tsmsESC;
  3101. FDesignatingCharacterSet := gcsG0;
  3102. end;
  3103. else
  3104. begin
  3105. FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' Character Set not implemented: &' + Ch);
  3106. FState := tsmsInitial;
  3107. FDesignatingCharacterSet := gcsG0;
  3108. end;
  3109. end;
  3110. end;
  3111. tsmsDesignateG0123CharacterSet96:
  3112. begin
  3113. case Ch of
  3114. 'A':
  3115. begin
  3116. if FDecConformanceLevel >= dclVT300 then
  3117. FGCharacterSets[FDesignatingCharacterSet] := dcsISOLatin1Supplemental;
  3118. FState := tsmsInitial;
  3119. FDesignatingCharacterSet := gcsG0;
  3120. end;
  3121. 'B':
  3122. begin
  3123. if FDecConformanceLevel >= dclVT500 then
  3124. FGCharacterSets[FDesignatingCharacterSet] := dcsISOLatin2Supplemental;
  3125. FState := tsmsInitial;
  3126. FDesignatingCharacterSet := gcsG0;
  3127. end;
  3128. 'F':
  3129. begin
  3130. if FDecConformanceLevel >= dclVT500 then
  3131. FGCharacterSets[FDesignatingCharacterSet] := dcsISOGreekSupplemental;
  3132. FState := tsmsInitial;
  3133. FDesignatingCharacterSet := gcsG0;
  3134. end;
  3135. 'H':
  3136. begin
  3137. if FDecConformanceLevel >= dclVT500 then
  3138. FGCharacterSets[FDesignatingCharacterSet] := dcsISOHebrewSupplemental;
  3139. FState := tsmsInitial;
  3140. FDesignatingCharacterSet := gcsG0;
  3141. end;
  3142. 'L':
  3143. begin
  3144. if FDecConformanceLevel >= dclVT500 then
  3145. FGCharacterSets[FDesignatingCharacterSet] := dcsISOLatinCyrillic;
  3146. FState := tsmsInitial;
  3147. FDesignatingCharacterSet := gcsG0;
  3148. end;
  3149. 'M':
  3150. begin
  3151. if FDecConformanceLevel >= dclVT500 then
  3152. FGCharacterSets[FDesignatingCharacterSet] := dcsISOLatin5Supplemental;
  3153. FState := tsmsInitial;
  3154. FDesignatingCharacterSet := gcsG0;
  3155. end;
  3156. #27:
  3157. begin
  3158. FState := tsmsESC;
  3159. FDesignatingCharacterSet := gcsG0;
  3160. end;
  3161. else
  3162. begin
  3163. FLogger.LogMessage(vlWarning, 'Designate G' + IntToStr(Ord(FDesignatingCharacterSet)) + ' 96-Character Set not implemented: ' + Ch);
  3164. FState := tsmsInitial;
  3165. FDesignatingCharacterSet := gcsG0;
  3166. end;
  3167. end;
  3168. end;
  3169. tsmsESC_SP:
  3170. begin
  3171. case Ch of
  3172. 'F':
  3173. begin
  3174. if FDecConformanceLevel >= dclVT200 then
  3175. Exclude(FModeFlags, tmfSend8BitC1Controls);
  3176. FState := tsmsInitial;
  3177. end;
  3178. 'G':
  3179. begin
  3180. if FDecConformanceLevel >= dclVT200 then
  3181. Include(FModeFlags, tmfSend8BitC1Controls);
  3182. FState := tsmsInitial;
  3183. end;
  3184. #27:
  3185. FState := tsmsESC;
  3186. else
  3187. begin
  3188. FLogger.LogMessage(vlWarning, 'Unhandled ESC SP sequence character: #' + IntToStr(Ord(Ch)));
  3189. FState := tsmsInitial;
  3190. end;
  3191. end;
  3192. end;
  3193. tsmsESC_Hash:
  3194. begin
  3195. case Ch of
  3196. { DEC Screen Alignment Test (DECALN), VT100 }
  3197. '8':
  3198. begin
  3199. for Y := 0 to FModel.Height - 1 do
  3200. for X := 0 to FModel.Width - 1 do
  3201. FModel.Cell[Y, X] := Cell('E', DefaultAttribute);
  3202. FScrollingRegionTop := 0;
  3203. FScrollingRegionBottom := FModel.Height - 1;
  3204. FModel.SetCursorPos(CursorHomeX, CursorHomeY);
  3205. FState := tsmsInitial;
  3206. end;
  3207. #27:
  3208. FState := tsmsESC;
  3209. else
  3210. begin
  3211. FLogger.LogMessage(vlWarning, 'Unhandled ESC # sequence character: #' + IntToStr(Ord(Ch)));
  3212. FState := tsmsInitial;
  3213. end;
  3214. end;
  3215. end;
  3216. tsmsESC_Percent:
  3217. begin
  3218. case Ch of
  3219. '@':
  3220. begin
  3221. Exclude(FModeFlags, tmfUTF8Mode);
  3222. FState := tsmsInitial;
  3223. end;
  3224. 'G':
  3225. begin
  3226. Include(FModeFlags, tmfUTF8Mode);
  3227. FState := tsmsInitial;
  3228. end;
  3229. #27:
  3230. FState := tsmsESC;
  3231. else
  3232. begin
  3233. FLogger.LogMessage(vlWarning, 'Unhandled ESC % sequence character: #' + IntToStr(Ord(Ch)));
  3234. FState := tsmsInitial;
  3235. end;
  3236. end;
  3237. end;
  3238. tsmsCSI:
  3239. begin
  3240. case Ch of
  3241. C0_CR:
  3242. HandleCR;
  3243. C0_VT,
  3244. C0_FF,
  3245. C0_LF:
  3246. HandleLF;
  3247. C0_BS:
  3248. HandleBS;
  3249. { Parameter Byte }
  3250. { 0123456789:;<=>? }
  3251. #$30..#$3F:
  3252. begin
  3253. if FControlSequenceIntermediate <> '' then
  3254. begin
  3255. { error }
  3256. FLogger.LogMessage(vlWarning, 'Invalid CSI control sequence parameter byte following after intermediate bytes: ' + FControlSequenceParameter + FControlSequenceIntermediate + Ch);
  3257. FState := tsmsInitial;
  3258. ClearControlSequence;
  3259. end
  3260. else
  3261. FControlSequenceParameter := FControlSequenceParameter + Ch;
  3262. end;
  3263. { Intermediate Byte }
  3264. { !"#$%&'()*+,-./ }
  3265. #$20..#$2F:
  3266. begin
  3267. FControlSequenceIntermediate := FControlSequenceIntermediate + Ch;
  3268. end;
  3269. { Final Byte }
  3270. //@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
  3271. #$40..#$7E:
  3272. begin
  3273. FControlSequenceFinalByte := Ch;
  3274. ExecuteControlSequence;
  3275. if FDecConformanceLevel = dclVT52 then
  3276. FState := tsmsVT52_Initial
  3277. else
  3278. FState := tsmsInitial;
  3279. ClearControlSequence;
  3280. end;
  3281. else
  3282. begin
  3283. { error }
  3284. FLogger.LogMessage(vlWarning, 'Unhandled CSI control sequence character: ' + FControlSequenceParameter + FControlSequenceIntermediate + Ch);
  3285. FState := tsmsInitial;
  3286. ClearControlSequence;
  3287. end;
  3288. end;
  3289. end;
  3290. tsmsOSC:
  3291. begin
  3292. case Ch of
  3293. #8..#13,#$20..#$7E:
  3294. FOperatingSystemCommand := FOperatingSystemCommand + Ch;
  3295. C1_ST:
  3296. begin
  3297. ExecuteOSC;
  3298. FOperatingSystemCommand := '';
  3299. FState := tsmsInitial;
  3300. end;
  3301. C0_ESC:
  3302. FState := tsmsOSC_ESC;
  3303. else
  3304. begin
  3305. FLogger.LogMessage(vlWarning, 'Invalid OSC control sequence character: ' + FOperatingSystemCommand + Ch);
  3306. FOperatingSystemCommand := '';
  3307. FState := tsmsInitial;
  3308. end;
  3309. end;
  3310. end;
  3311. tsmsOSC_ESC:
  3312. begin
  3313. case Ch of
  3314. Chr(Ord(C1_ST) - $40):
  3315. begin
  3316. ExecuteOSC;
  3317. FOperatingSystemCommand := '';
  3318. FState := tsmsInitial;
  3319. end;
  3320. else
  3321. begin
  3322. FLogger.LogMessage(vlWarning, 'Invalid OSC control sequence character: ' + FOperatingSystemCommand + #27 + Ch);
  3323. FOperatingSystemCommand := '';
  3324. FState := tsmsInitial;
  3325. end;
  3326. end;
  3327. end;
  3328. tsmsDCS:
  3329. begin
  3330. case Ch of
  3331. #8..#13,#$20..#$7E:
  3332. FDeviceControlString := FDeviceControlString + Ch;
  3333. C1_ST:
  3334. begin
  3335. ExecuteDCS;
  3336. FDeviceControlString := '';
  3337. FState := tsmsInitial;
  3338. end;
  3339. C0_ESC:
  3340. FState := tsmsDCS_ESC;
  3341. else
  3342. begin
  3343. FLogger.LogMessage(vlWarning, 'Invalid DCS control sequence character: ' + FDeviceControlString + Ch);
  3344. FDeviceControlString := '';
  3345. FState := tsmsInitial;
  3346. end;
  3347. end;
  3348. end;
  3349. tsmsDCS_ESC:
  3350. begin
  3351. case Ch of
  3352. Chr(Ord(C1_ST) - $40):
  3353. begin
  3354. ExecuteDCS;
  3355. FDeviceControlString := '';
  3356. FState := tsmsInitial;
  3357. end;
  3358. else
  3359. begin
  3360. FLogger.LogMessage(vlWarning, 'Invalid DCS control sequence character: ' + FDeviceControlString + #27 + Ch);
  3361. FDeviceControlString := '';
  3362. FState := tsmsInitial;
  3363. end;
  3364. end;
  3365. end;
  3366. tsmsUTF8_1ByteLeft:
  3367. begin
  3368. case Ch of
  3369. #%10000000..#%10111111:
  3370. begin
  3371. FUTF8_Build := (FUTF8_Build shl 6) or (Ord(Ch) and %111111);
  3372. WriteUTF32Char(FUTF8_Build);
  3373. FState := tsmsInitial;
  3374. end;
  3375. else
  3376. begin
  3377. { error }
  3378. FLogger.LogMessage(vlWarning, 'Invalid UTF-8 continuation byte: #' + IntToStr(Ord(Ch)));
  3379. FState := tsmsInitial;
  3380. FUTF8_Build := 0;
  3381. end;
  3382. end;
  3383. end;
  3384. tsmsUTF8_2BytesLeft:
  3385. begin
  3386. case Ch of
  3387. #%10000000..#%10111111:
  3388. begin
  3389. FUTF8_Build := (FUTF8_Build shl 6) or (Ord(Ch) and %111111);
  3390. FState := tsmsUTF8_1ByteLeft;
  3391. end;
  3392. else
  3393. begin
  3394. { error }
  3395. FLogger.LogMessage(vlWarning, 'Invalid UTF-8 continuation byte: #' + IntToStr(Ord(Ch)));
  3396. FState := tsmsInitial;
  3397. FUTF8_Build := 0;
  3398. end;
  3399. end;
  3400. end;
  3401. tsmsUTF8_3BytesLeft:
  3402. begin
  3403. case Ch of
  3404. #%10000000..#%10111111:
  3405. begin
  3406. FUTF8_Build := (FUTF8_Build shl 6) or (Ord(Ch) and %111111);
  3407. FState := tsmsUTF8_2BytesLeft;
  3408. end;
  3409. else
  3410. begin
  3411. { error }
  3412. FLogger.LogMessage(vlWarning, 'Invalid UTF-8 continuation byte: #' + IntToStr(Ord(Ch)));
  3413. FState := tsmsInitial;
  3414. FUTF8_Build := 0;
  3415. end;
  3416. end;
  3417. end;
  3418. tsmsVT52_Initial:
  3419. begin
  3420. case Chr(Ord(Ch) and 127) of
  3421. C0_CR:
  3422. HandleCR;
  3423. C0_LF:
  3424. HandleLF;
  3425. C0_BS:
  3426. HandleBS;
  3427. C0_HT:
  3428. HandleHT;
  3429. C0_ESC:
  3430. FState := tsmsVT52_ESC;
  3431. #32..#126:
  3432. WriteVT52Char(Ch);
  3433. else
  3434. FLogger.LogMessage(vlWarning, 'Unhandled character (VT52 mode): #' + IntToStr(Ord(Ch)));
  3435. end;
  3436. end;
  3437. tsmsVT52_ESC:
  3438. begin
  3439. case Chr(Ord(Ch) and 127) of
  3440. { Exit VT52 mode (Enter VT100 mode). }
  3441. '<':
  3442. if TerminalType >= ttVT100 then
  3443. LeaveVT52Mode;
  3444. { Cursor up. }
  3445. 'A':
  3446. begin
  3447. FModel.SetCursorPos(FModel.CursorX, Max(FModel.CursorY - 1, 0));
  3448. FNextCharacterWrapsToNextLine := False;
  3449. FState := tsmsVT52_Initial;
  3450. end;
  3451. { Cursor down. }
  3452. 'B':
  3453. begin
  3454. FModel.SetCursorPos(FModel.CursorX, Min(FModel.CursorY + 1, FModel.Height - 1));
  3455. FNextCharacterWrapsToNextLine := False;
  3456. FState := tsmsVT52_Initial;
  3457. end;
  3458. { Cursor right. }
  3459. 'C':
  3460. begin
  3461. FModel.SetCursorPos(Min(FModel.CursorX + 1, FModel.Width - 1), FModel.CursorY);
  3462. FNextCharacterWrapsToNextLine := False;
  3463. FState := tsmsVT52_Initial;
  3464. end;
  3465. { Cursor left. }
  3466. 'D':
  3467. begin
  3468. FModel.SetCursorPos(Max(FModel.CursorX - 1, 0), FModel.CursorY);
  3469. FNextCharacterWrapsToNextLine := False;
  3470. FState := tsmsVT52_Initial;
  3471. end;
  3472. { Enter graphics mode. }
  3473. 'F':
  3474. begin
  3475. FVT52CharacterSet := v52csGraphics;
  3476. FState := tsmsVT52_Initial;
  3477. end;
  3478. { Exit graphics mode. }
  3479. 'G':
  3480. begin
  3481. FVT52CharacterSet := v52csAscii;
  3482. FState := tsmsVT52_Initial;
  3483. end;
  3484. { Move the cursor to the home position. }
  3485. 'H':
  3486. begin
  3487. FModel.SetCursorPos(0, 0);
  3488. FNextCharacterWrapsToNextLine := False;
  3489. FState := tsmsVT52_Initial;
  3490. end;
  3491. { Reverse line feed. }
  3492. 'I':
  3493. begin
  3494. HandleC1(C1_RI);
  3495. FState := tsmsVT52_Initial;
  3496. end;
  3497. { Erase from the cursor to the end of the screen. }
  3498. 'J':
  3499. begin
  3500. ErasePageToBottom;
  3501. FState := tsmsVT52_Initial;
  3502. end;
  3503. { Erase from the cursor to the end of the line. }
  3504. 'K':
  3505. begin
  3506. EraseLineToRight;
  3507. FState := tsmsVT52_Initial;
  3508. end;
  3509. 'Y':
  3510. FState := tsmsVT52_ESC_Y;
  3511. { Identify. }
  3512. 'Z':
  3513. begin
  3514. { "I am a VT52." }
  3515. TransmitStr(#27'/Z');
  3516. end;
  3517. else
  3518. begin
  3519. { error }
  3520. FLogger.LogMessage(vlWarning, 'Unhandled ESC sequence character (VT52 mode): #' + IntToStr(Ord(Ch)));
  3521. FState := tsmsVT52_Initial;
  3522. end;
  3523. end;
  3524. end;
  3525. tsmsVT52_ESC_Y:
  3526. begin
  3527. case Chr(Ord(Ch) and 127) of
  3528. #32..#127:
  3529. begin
  3530. FModel.SetCursorPos(FModel.CursorX, EnsureRange((Ord(Ch) and 127) - 32, 0, FModel.Height - 1));
  3531. FState := tsmsVT52_ESC_Y_Ps;
  3532. end;
  3533. else
  3534. FLogger.LogMessage(vlWarning, 'Unhandled ESC Y sequence character (VT52 mode): #' + IntToStr(Ord(Ch)));
  3535. end;
  3536. end;
  3537. tsmsVT52_ESC_Y_Ps:
  3538. begin
  3539. case Chr(Ord(Ch) and 127) of
  3540. #32..#127:
  3541. begin
  3542. FModel.SetCursorPos(EnsureRange((Ord(Ch) and 127) - 32, 0, FModel.Width - 1), FModel.CursorY);
  3543. FState := tsmsVT52_Initial;
  3544. end;
  3545. else
  3546. FLogger.LogMessage(vlWarning, 'Unhandled ESC Y Ps sequence character (VT52 mode): #' + IntToStr(Ord(Ch)));
  3547. end;
  3548. end;
  3549. end;
  3550. end;
  3551. FModel.UpdateScreen;
  3552. end;
  3553. procedure TTerminalController.MaybeLocalEcho(const ks: rawbytestring);
  3554. begin
  3555. if not (tmfSendReceiveMode in FModeFlags) then
  3556. begin
  3557. { todo: handle non-ASCII characters }
  3558. if (Length(ks) = 1) and ((Ord(ks[1]) >= 32) and (Ord(ks[1]) <= 126)) then
  3559. ReceiveData(ks[1], 1);
  3560. end;
  3561. end;
  3562. procedure TTerminalController.HandleMouseEvent(const pdev: TPointingDeviceEvent);
  3563. procedure SendX10MouseEvent(X, Y, Button: Integer; Press: Boolean);
  3564. var
  3565. PressChar: Char;
  3566. begin
  3567. if (X < 0) or (Y < 0) or (Button < 0) then
  3568. exit;
  3569. if Press then
  3570. PressChar := 'M'
  3571. else
  3572. PressChar := 'm';
  3573. case FMouseProtocolEncoding of
  3574. tmpeX10:
  3575. begin
  3576. if ((32 + X) > 255) or ((32 + Y) > 255) or ((32 + Button) > 255) then
  3577. exit;
  3578. TransmitStr(EncodeReturnC1(C1_CSI) + PressChar + Chr(32 + Button) + Chr(32 + X) + Chr(32 + Y));
  3579. end;
  3580. tmpeUTF8:
  3581. begin
  3582. if (X > 2015) or (Y > 2015) or (Button > 2015) then
  3583. exit;
  3584. TransmitStr(EncodeReturnC1(C1_CSI) + PressChar + UTF8Encode(WideChar(32 + Button)) + UTF8Encode(WideChar(32 + X)) + UTF8Encode(WideChar(32 + Y)));
  3585. end;
  3586. tmpeSGR:
  3587. TransmitStr(EncodeReturnC1(C1_CSI) + '<' + IntToStr(Button) + ';' + IntToStr(X) + ';' + IntToStr(Y) + PressChar);
  3588. end;
  3589. end;
  3590. var
  3591. MouseX, MouseY: Integer;
  3592. MouseMoved: Boolean;
  3593. ButtonsPressed, ButtonsReleased: TPointingDeviceButtonState;
  3594. procedure SendNormalEvent;
  3595. const
  3596. ButtonTranslation: array [pdButton1..pdButton11] of Integer = (0, 2, 1, 64, 65, 66, 67, 128, 129, 130, 131);
  3597. var
  3598. Mask: Byte = 0;
  3599. B: TPointingDeviceButton;
  3600. begin
  3601. for B := Low(ButtonTranslation) to High(ButtonTranslation) do
  3602. if B in ButtonsPressed then
  3603. SendX10MouseEvent(MouseX + 1, MouseY + 1, ButtonTranslation[B] or Mask, True);
  3604. for B := Low(ButtonTranslation) to High(ButtonTranslation) do
  3605. if B in ButtonsReleased then
  3606. SendX10MouseEvent(MouseX + 1, MouseY + 1, ButtonTranslation[B] or Mask, False);
  3607. if (ButtonsPressed = []) and (ButtonsReleased = []) then
  3608. begin
  3609. if not MouseMoved then
  3610. exit;
  3611. if pdev.ButtonState = [] then
  3612. SendX10MouseEvent(MouseX + 1, MouseY + 1, (32 + 3) or Mask, True)
  3613. else
  3614. for B := Low(ButtonTranslation) to High(ButtonTranslation) do
  3615. if B in pdev.ButtonState then
  3616. begin
  3617. SendX10MouseEvent(MouseX + 1, MouseY + 1, ButtonTranslation[B] or 32 or Mask, True);
  3618. break;
  3619. end;
  3620. end;
  3621. end;
  3622. begin
  3623. MouseX := pdev.X;
  3624. MouseY := pdev.Y;
  3625. MouseMoved := (MouseX <> FOldMouseX) or (MouseY <> FOldMouseY);
  3626. ButtonsPressed := pdev.ButtonState - FOldMouseButtons;
  3627. ButtonsReleased := FOldMouseButtons - pdev.ButtonState;
  3628. case FMouseTrackingMode of
  3629. tmtmX10:
  3630. if ButtonsPressed <> [] then
  3631. begin
  3632. if pdButton1 in ButtonsPressed then
  3633. SendX10MouseEvent(MouseX + 1, MouseY + 1, 0, True);
  3634. if pdButton2 in ButtonsPressed then
  3635. SendX10MouseEvent(MouseX + 1, MouseY + 1, 2, True);
  3636. if pdButton3 in ButtonsPressed then
  3637. SendX10MouseEvent(MouseX + 1, MouseY + 1, 1, True);
  3638. end;
  3639. tmtmNormal:
  3640. if (ButtonsPressed <> []) or (ButtonsReleased <> []) then
  3641. SendNormalEvent;
  3642. tmtmButtonEvent:
  3643. if (ButtonsPressed <> []) or (ButtonsReleased <> []) or (pdev.ButtonState <> []) then
  3644. SendNormalEvent;
  3645. tmtmAnyEvent:
  3646. SendNormalEvent;
  3647. end;
  3648. FOldMouseX := MouseX;
  3649. FOldMouseY := MouseY;
  3650. FOldMouseButtons := pdev.ButtonState;
  3651. end;
  3652. function TTerminalController.EncodeReturnC1(Ch: TC1Char): string;
  3653. begin
  3654. if tmfSend8BitC1Controls in FModeFlags then
  3655. Result := Ch
  3656. else
  3657. Result := #27 + Chr(Ord(Ch) - $40);
  3658. end;
  3659. end.