VT100.cs
上传用户:szltgg
上传日期:2019-05-16
资源大小:604k
文件大小:19k
源码类别:

Telnet服务器

开发平台:

C#

  1. /*
  2. * Copyright (c) 2005 Poderosa Project, All Rights Reserved.
  3. * $Id: VT100.cs,v 1.2 2005/04/20 08:45:48 okajima Exp $
  4. */
  5. using System;
  6. using System.IO;
  7. using System.Text;
  8. using System.Diagnostics;
  9. using System.Drawing;
  10. using System.Windows.Forms;
  11. using Poderosa.Connection;
  12. using Poderosa.ConnectionParam;
  13. using Poderosa.Text;
  14. using Poderosa.UI;
  15. namespace Poderosa.Terminal
  16. {
  17. internal class VT100Terminal : EscapeSequenceTerminal {
  18. protected int _savedRow;
  19. protected int _savedCol;
  20. protected bool _insertMode;
  21. protected bool _scrollRegionRelative;
  22. //愙懕偺庬椶偵傛偭偰僄僗働乕僾僔乕働儞僗偺夝庍傪曄偊傞晹暘
  23. protected bool _homePositionOnCSIJ2;
  24. public VT100Terminal(ConnectionTag tag, ICharDecoder decoder) : base(tag, decoder) {
  25. _insertMode = false;
  26. _scrollRegionRelative = false;
  27. bool sfu = tag.Connection.Param is SFUTerminalParam;
  28. _homePositionOnCSIJ2 = sfu;
  29. }
  30. protected override void ResetInternal() {
  31. base.ResetInternal();
  32. _insertMode = false;
  33. _scrollRegionRelative = false;
  34. }
  35. protected override ProcessCharResult ProcessEscapeSequence(char code, char[] seq, int offset) {
  36. string param;
  37. switch(code) {
  38. case '[':
  39. if(seq.Length-offset-1>=0) {
  40. param = new string(seq, offset, seq.Length-offset-1);
  41. return ProcessAfterCSI(param, seq[seq.Length-1]);
  42. }
  43. break;
  44. //throw new UnknownEscapeSequenceException(String.Format("unknown command after CSI {0}", code));
  45. case ']':
  46. if(seq.Length-offset-1>=0) {
  47. param = new string(seq, offset, seq.Length-offset-1);
  48. return ProcessAfterOSC(param, seq[seq.Length-1]);
  49. }
  50. break;
  51. case '=':
  52. ChangeMode(TerminalMode.Application);
  53. return ProcessCharResult.Processed;
  54. case '>':
  55. ChangeMode(TerminalMode.Normal);
  56. return ProcessCharResult.Processed;
  57. case 'E':
  58. ProcessNextLine();
  59. return ProcessCharResult.Processed;
  60. case 'M': 
  61. ReverseIndex();
  62. return ProcessCharResult.Processed;
  63. case 'D': 
  64. Index();
  65. return ProcessCharResult.Processed;
  66. case '7':
  67. SaveCursor();
  68. return ProcessCharResult.Processed;
  69. case '8':
  70. RestoreCursor();
  71. return ProcessCharResult.Processed;
  72. case 'c':
  73. FullReset();
  74. return ProcessCharResult.Processed;
  75. }
  76. return ProcessCharResult.Unsupported;
  77. }
  78. protected virtual ProcessCharResult ProcessAfterCSI(string param, char code) {
  79. switch(code) {
  80. case 'c':
  81. ProcessDeviceAttributes(param);
  82. break;
  83. case 'm': //SGR
  84. ProcessSGR(param);
  85. break;
  86. case 'h':
  87. case 'l':
  88. return ProcessDECSETMulti(param, code);
  89. case 'r':
  90. if(param.Length>0 && param[0]=='?')
  91. return ProcessRestoreDECSET(param, code);
  92. else
  93. ProcessSetScrollingRegion(param);
  94. break;
  95. case 's':
  96. return ProcessSaveDECSET(param, code);
  97. case 'n':
  98. ProcessDeviceStatusReport(param);
  99. break;
  100. case 'A':
  101. case 'B':
  102. case 'C':
  103. case 'D':
  104. case 'E':
  105. case 'F':
  106. ProcessCursorMove(param, code);
  107. break;
  108. case 'H':
  109. case 'f': //f偼杮摉偼xterm屌桳
  110. ProcessCursorPosition(param);
  111. break;
  112. case 'J':
  113. ProcessEraseInDisplay(param);
  114. break;
  115. case 'K':
  116. ProcessEraseInLine(param);
  117. break;
  118. case 'L':
  119. ProcessInsertLines(param);
  120. break;
  121. case 'M':
  122. ProcessDeleteLines(param);
  123. break;
  124. default:
  125. return ProcessCharResult.Unsupported; 
  126. }
  127. return ProcessCharResult.Processed;
  128. }
  129. protected virtual ProcessCharResult ProcessAfterOSC(string param, char code) {
  130. return ProcessCharResult.Unsupported;
  131. }
  132. protected void ProcessSGR(string param) {
  133. string[] ps = param.Split(';');
  134. foreach(string cmd in ps) {
  135. TextDecoration dec = (TextDecoration)_currentdecoration.Clone();
  136. int code = ParseSGRCode(cmd);
  137. if(code>=30 && code<=37) {
  138. //偙傟偩偲怓傪曄峏偟偨偲偒婛偵夋柺偵偁傞傕偺偼楢摦偟側偔側傞偑丄偦偙傪偪傖傫偲偡傞偺偼崲擄偱偁傞
  139. dec.TextColor = _tag.GetCurrentRenderProfile().ESColorSet[code % 10];
  140. }
  141. else if(code>=40 && code<=47) {
  142. Color c = _tag.GetCurrentRenderProfile().ESColorSet[code % 10];
  143. dec.BackColor = DrawUtil.DarkColor(c); //攚宨怓偼埫傔偵
  144. }
  145. else {
  146. switch(code) {
  147. case 0:
  148. dec = TextDecoration.ClonedDefault();
  149. break;
  150. case 1:
  151. case 5:
  152. dec.Bold = true;
  153. break;
  154. case 4:
  155. dec.Underline = true;
  156. break;
  157. case 7:
  158. dec.Inverse();
  159. break;
  160. case 2:
  161. dec = TextDecoration.ClonedDefault(); //晄柧偩偑SGR 2偱廔傢偭偰偄傞椺偑偁偭偨
  162. break;
  163. case 22:
  164. case 25:
  165. case 27:
  166. case 28:
  167. dec = TextDecoration.ClonedDefault();
  168. break;
  169. case 24:
  170. dec.Underline = false;
  171. break;
  172. case 39:
  173. dec.TextColorType = ColorType.DefaultText;
  174. break;
  175. case 49:
  176. dec.BackColorType = ColorType.DefaultBack;
  177. break;
  178. case 10:
  179. case 11:
  180. case 12:
  181. break; //'konsole'偲偄偆傗偮傜偟偄丅柍帇偱栤戣側偝偦偆
  182. default:
  183. throw new UnknownEscapeSequenceException(String.Format("unknown SGR command {0}", param));
  184. }
  185. }
  186. _currentdecoration = dec;
  187. //_manipulator.SetDecoration(dec);
  188. }
  189. }
  190. private static int ParseSGRCode(string param) {
  191. if(param.Length==0)
  192. return 0;
  193. else if(param.Length==1)
  194. return param[0]-'0';
  195. else if(param.Length==2)
  196. return (param[0]-'0')*10 + (param[1]-'0');
  197. else
  198. throw new UnknownEscapeSequenceException(String.Format("unknown SGR parameter {0}", param));
  199. }
  200. protected virtual void ProcessDeviceAttributes(string param) {
  201. byte[] data = Encoding.ASCII.GetBytes(" [?1;2c"); //側傫偐傛偔傢偐傜側偄偑MindTerm摍傪傒傞偲偙傟偱偄偄傜偟偄
  202. data[0] = 0x1B; //ESC
  203. GetConnection().Write(data);
  204. }
  205. protected virtual void ProcessDeviceStatusReport(string param) {
  206. string response;
  207. if(param=="5")
  208. response = " [0n"; //偙傟偱OK偺堄枴傜偟偄
  209. else if(param=="6")
  210. response = String.Format(" [{0};{1}R", GetDocument().CurrentLineNumber-GetDocument().TopLineNumber+1, _manipulator.CaretColumn+1);
  211. else
  212. throw new UnknownEscapeSequenceException("DSR " + param);
  213. byte[] data = Encoding.ASCII.GetBytes(response);
  214. data[0] = 0x1B; //ESC
  215. GetConnection().Write(data);
  216. }
  217. protected void ProcessCursorMove(string param, char method) {
  218. int count = ParseInt(param, 1); //僷儔儊乕僞偑徣棯偝傟偨偲偒偺堏摦検偼侾
  219. int column = _manipulator.CaretColumn;
  220. switch(method) {
  221. case 'A':
  222. GetDocument().ReplaceCurrentLine(_manipulator.Export());
  223. GetDocument().CurrentLineNumber = (GetDocument().CurrentLineNumber - count);
  224. _manipulator.Load(GetDocument().CurrentLine, column);
  225. break;
  226. case 'B':
  227. GetDocument().ReplaceCurrentLine(_manipulator.Export());
  228. GetDocument().CurrentLineNumber = (GetDocument().CurrentLineNumber + count);
  229. _manipulator.Load(GetDocument().CurrentLine, column);
  230. break;
  231. case 'C': {
  232. int newvalue = column + count;
  233. if(newvalue >= GetConnection().TerminalWidth) newvalue = GetConnection().TerminalWidth-1;
  234. _manipulator.ExpandBuffer(newvalue);
  235. _manipulator.CaretColumn = newvalue;
  236. }
  237. break;
  238. case 'D': {
  239. int newvalue = column - count;
  240. if(newvalue < 0) newvalue = 0;
  241. _manipulator.CaretColumn = newvalue;
  242. }
  243. break;
  244. }
  245. }
  246. //CSI H
  247. protected void ProcessCursorPosition(string param) {
  248. IntPair t = ParseIntPair(param, 1, 1);
  249. int row = t.first, col = t.second;
  250. if(_scrollRegionRelative && GetDocument().ScrollingTop!=-1) {
  251. row += GetDocument().ScrollingTop;
  252. }
  253. if(row<1) row=1;
  254. else if(row>GetConnection().TerminalHeight) row = GetConnection().TerminalHeight;
  255. if(col<1) col=1;
  256. else if(col>GetConnection().TerminalWidth) col = GetConnection().TerminalWidth;
  257. ProcessCursorPosition(row, col);
  258. }
  259. protected void ProcessCursorPosition(int row, int col) {
  260. GetDocument().ReplaceCurrentLine(_manipulator.Export());
  261. GetDocument().CurrentLineNumber = (GetDocument().TopLineNumber + row - 1);
  262. //int cc = GetDocument().CurrentLine.DisplayPosToCharPos(col-1);
  263. //Debug.Assert(cc>=0);
  264. _manipulator.Load(GetDocument().CurrentLine, col-1);
  265. }
  266. //CSI J
  267. protected void ProcessEraseInDisplay(string param) {
  268. int d = ParseInt(param, 0);
  269. TerminalDocument doc = GetDocument();
  270. int col = _manipulator.CaretColumn;
  271. switch(d) {
  272. case 0: //erase below
  273. _manipulator.RemoveAfterCaret(); 
  274. doc.ReplaceCurrentLine(_manipulator.Export());
  275. doc.RemoveAfter(doc.TopLineNumber+GetConnection().TerminalHeight);
  276. if(_currentdecoration.IsDefault)
  277. doc.ClearAfter(doc.CurrentLineNumber+1);
  278. else
  279. doc.ClearAfter(doc.CurrentLineNumber+1, _currentdecoration);
  280. _manipulator.Load(doc.CurrentLine, col);
  281. break;
  282. case 1: //erase above
  283. _manipulator.FillSpace(0, _manipulator.CaretColumn);
  284. doc.ReplaceCurrentLine(_manipulator.Export());
  285. if(_currentdecoration.IsDefault)
  286. doc.ClearRange(doc.TopLineNumber, doc.CurrentLineNumber);
  287. else
  288. doc.ClearRange(doc.TopLineNumber, doc.CurrentLineNumber, _currentdecoration);
  289. _manipulator.Load(doc.CurrentLine, col);
  290. break;
  291. case 2: //erase all
  292. doc.ReplaceCurrentLine(_manipulator.Export());
  293. if(_homePositionOnCSIJ2) { //SFU偱偼偙偆側傞
  294. ProcessCursorPosition(1,1); 
  295. col = 0;
  296. }
  297. if(_currentdecoration.IsDefault)
  298. doc.ClearAfter(doc.TopLineNumber);
  299. else
  300. doc.ClearAfter(doc.TopLineNumber, _currentdecoration);
  301. _manipulator.Load(doc.CurrentLine, col);
  302. break;
  303. default:
  304. throw new UnknownEscapeSequenceException(String.Format("unknown ED option {0}", param));
  305. }
  306. }
  307. //CSI K
  308. private void ProcessEraseInLine(string param) {
  309. int d = ParseInt(param, 0);
  310. switch(d) {
  311. case 0: //erase right
  312. if(_currentdecoration.IsDefault)
  313. _manipulator.RemoveAfterCaret();
  314. else 
  315. _manipulator.FillSpace(_manipulator.CaretColumn, _tag.Connection.TerminalWidth, _currentdecoration);
  316. break;
  317. case 1: //erase left
  318. _manipulator.FillSpace(0, _manipulator.CaretColumn);
  319. break;
  320. case 2: //erase all
  321. _manipulator.Clear(_tag.Connection.TerminalWidth);
  322. break;
  323. default:
  324. throw new UnknownEscapeSequenceException(String.Format("unknown EL option {0}", param));
  325. }
  326. }
  327. protected void SaveCursor() {
  328. _savedRow = GetDocument().CurrentLineNumber - GetDocument().TopLineNumber;
  329. _savedCol = _manipulator.CaretColumn;
  330. }
  331. protected void RestoreCursor() {
  332. GLine nl = _manipulator.Export();
  333. GetDocument().ReplaceCurrentLine(nl);
  334. GetDocument().CurrentLineNumber = GetDocument().TopLineNumber + _savedRow;
  335. _manipulator.Load(GetDocument().CurrentLine, _savedCol);
  336. }
  337. protected void Index() {
  338. GLine nl = _manipulator.Export();
  339. GetDocument().ReplaceCurrentLine(nl);
  340. int current = GetDocument().CurrentLineNumber;
  341. if(current==GetDocument().TopLineNumber+GetConnection().TerminalHeight-1 || current==GetDocument().ScrollingBottom)
  342. GetDocument().ScrollDown();
  343. else
  344. GetDocument().CurrentLineNumber = current+1;
  345. _manipulator.Load(GetDocument().CurrentLine, _manipulator.CaretColumn);
  346. }
  347. protected void ReverseIndex() {
  348. GLine nl = _manipulator.Export();
  349. GetDocument().ReplaceCurrentLine(nl);
  350. int current = GetDocument().CurrentLineNumber;
  351. if(current==GetDocument().TopLineNumber || current==GetDocument().ScrollingTop)
  352. GetDocument().ScrollUp();
  353. else
  354. GetDocument().CurrentLineNumber = current-1;
  355. _manipulator.Load(GetDocument().CurrentLine, _manipulator.CaretColumn);
  356. }
  357. protected void ProcessSetScrollingRegion(string param) {
  358. int height = _tag.Connection.TerminalHeight;
  359. IntPair v = ParseIntPair(param, 1, height);
  360. if(v.first<1) v.first = 1;
  361. else if(v.first>height) v.first = height;
  362. if(v.second<1) v.second = 1;
  363. else if(v.second>height) v.second = height;
  364. if(v.first>v.second) { //栤摎柍梡偱僄儔乕偑椙偄傛偆偵傕巚偆偑
  365. int t = v.first;
  366. v.first = v.second;
  367. v.second = t;
  368. }
  369. //巜掕偼1-origin偩偑張棟偼0-origin
  370. GetDocument().SetScrollingRegion(v.first-1, v.second-1);
  371. }
  372. protected void ProcessNextLine() {
  373. GetDocument().ReplaceCurrentLine(_manipulator.Export());
  374. GetDocument().CurrentLineNumber = (GetDocument().CurrentLineNumber + 1);
  375. _manipulator.Load(GetDocument().CurrentLine, 0);
  376. }
  377. protected override void ChangeMode(TerminalMode mode) {
  378. if(_terminalMode==mode) return;
  379. if(mode==TerminalMode.Normal) {
  380. GetDocument().ClearScrollingRegion();
  381. GetConnection().Resize(GetConnection().TerminalWidth, GetConnection().TerminalHeight); //偨偲偊偽emacs婲摦拞偵儕僒僀僘偟丄僔僃儖傊栠傞偲僔僃儖偼怴偟偄僒僀僘傪擣幆偟偰偄側偄
  382. //RMBox偱妋擣偝傟偨偙偲偩偑丄柍梡偵屻曽偵僪僉儏儊儞僩傪峀偘偰偔傞搝偑偄傞丅僇乕僜儖傪123夞屻曽傊丄側偳丅
  383. //応摉偨傝揑偩偑丄僲乕儅儖儌乕僪偵栠傞嵺偵屻傠偺嬻峴傪嶍彍偡傞偙偲偱懳墳偡傞丅
  384. GLine l = GetDocument().LastLine;
  385. while(l!=null && l.DisplayLength==0 && l.ID>GetDocument().CurrentLineNumber)
  386. l = l.PrevLine;
  387. if(l!=null) l = l.NextLine;
  388. if(l!=null) GetDocument().RemoveAfter(l.ID);
  389. }
  390. else
  391. GetDocument().SetScrollingRegion(0, _tag.Connection.TerminalHeight-1);
  392. _terminalMode = mode;
  393. }
  394. private ProcessCharResult ProcessDECSETMulti(string param, char code) {
  395. if(param.Length==0) return ProcessCharResult.Processed;
  396. bool question = param[0]=='?';
  397. string[] ps = question? param.Substring(1).Split(';') : param.Split(';');
  398. bool unsupported = false;
  399. foreach(string p in ps) {
  400. ProcessCharResult r = question? ProcessDECSET(p, code) : ProcessSetMode(p, code);
  401. if(r==ProcessCharResult.Unsupported) unsupported = true;
  402. }
  403. return unsupported? ProcessCharResult.Unsupported : ProcessCharResult.Processed;
  404. }
  405. //CSI ? Pm h, CSI ? Pm l
  406. protected virtual ProcessCharResult ProcessDECSET(string param, char code) {
  407. //Debug.WriteLine(String.Format("DECSET {0} {1}", param, code));
  408. if(param=="25") {
  409. return ProcessCharResult.Processed; //!!Show/Hide Cursor偩偑偲傝偁偊偢柍帇
  410. }
  411. else if(param=="1") {
  412. ChangeCursorKeyMode(code=='h'? TerminalMode.Application : TerminalMode.Normal);
  413. return ProcessCharResult.Processed;
  414. }
  415. else
  416. return ProcessCharResult.Unsupported;
  417. }
  418. protected virtual ProcessCharResult ProcessSetMode(string param, char code) {
  419. if(param=="4") {
  420. _insertMode = code=='h'; //h偱巒傑偭偰l偱廔傢傞
  421. return ProcessCharResult.Processed;
  422. }
  423. else if(param=="20") {
  424. return ProcessCharResult.Processed; //!!WinXP偺Telnet偱妋擣偟偨
  425. }
  426. else
  427. return ProcessCharResult.Unsupported;
  428. }
  429. //偙傟偼偝傏傝丅偪傖傫偲曐懚偟側偄偲偄偗側偄忬懺偼傎偲傫偳側偄偺偱
  430. protected virtual ProcessCharResult ProcessSaveDECSET(string param, char code) {
  431. //偙偺param偼暋悢屄僷儔儊乕僞
  432. return ProcessCharResult.Processed;
  433. }
  434. protected virtual ProcessCharResult ProcessRestoreDECSET(string param, char code) {
  435. //偙偺param偼暋悢屄僷儔儊乕僞
  436. return ProcessCharResult.Processed;
  437. }
  438. //偙傟傪憲偭偰偔傞傾僾儕働乕僔儑儞偼 vi偱忋曽僗僋儘乕儖
  439. protected void ProcessInsertLines(string param) {
  440. int d = ParseInt(param, 1);
  441. /*
  442. TerminalDocument doc = GetDocument();
  443. for(int i=0; i<d; i++)
  444. doc.InsertAfter(doc.CurrentLine, new GLine(GetConnection().TerminalWidth));
  445. */
  446. TerminalDocument doc = GetDocument();
  447. int caret_pos = _manipulator.CaretColumn;
  448. int offset = doc.CurrentLineNumber - doc.TopLineNumber;
  449. GLine nl = _manipulator.Export();
  450. doc.ReplaceCurrentLine(nl);
  451. if(doc.ScrollingBottom==-1)
  452. doc.SetScrollingRegion(0, GetConnection().TerminalHeight-1);
  453. for(int i=0; i<d; i++) {
  454. doc.ScrollUp(doc.CurrentLineNumber, doc.ScrollingBottom);
  455. doc.CurrentLineNumber = doc.TopLineNumber + offset;
  456. }
  457. _manipulator.Load(doc.CurrentLine, caret_pos);
  458. }
  459. //偙傟傪憲偭偰偔傞傾僾儕働乕僔儑儞偼 vi偱壓曽僗僋儘乕儖
  460. protected void ProcessDeleteLines(string param) {
  461. int d = ParseInt(param, 1);
  462. /*
  463. TerminalDocument doc = GetDocument();
  464. _manipulator.Clear(GetConnection().TerminalWidth);
  465. GLine target = doc.CurrentLine;
  466. for(int i=0; i<d; i++) {
  467. target.Clear();
  468. target = target.NextLine;
  469. }
  470. */
  471. TerminalDocument doc = GetDocument();
  472. int caret_col = _manipulator.CaretColumn;
  473. int offset = doc.CurrentLineNumber - doc.TopLineNumber;
  474. GLine nl = _manipulator.Export();
  475. doc.ReplaceCurrentLine(nl);
  476. if(doc.ScrollingBottom==-1)
  477. doc.SetScrollingRegion(0, GetConnection().TerminalHeight-1);
  478. for(int i=0; i<d; i++) {
  479. doc.ScrollDown(doc.CurrentLineNumber, doc.ScrollingBottom);
  480. doc.CurrentLineNumber = doc.TopLineNumber + offset;
  481. }
  482. _manipulator.Load(doc.CurrentLine, caret_col);
  483. }
  484. private static string[] FUNCTIONKEY_MAP = { 
  485. //     F1    F2    F3    F4    F5    F6    F7    F8    F9    F10   F11  F12
  486.   "11", "12", "13", "14", "15", "17", "18", "19", "20", "21", "23", "24",
  487.     //     F13   F14   F15   F16   F17  F18   F19   F20   F21   F22
  488.               "25", "26", "28", "29", "31", "32", "33", "34", "23", "24" };
  489. //摿掕偺僨乕僞傪棳偡僞僀僾丅尰嵼丄僇乕僜儖僉乕偲僼傽儞僋僔儑儞僉乕偑奩摉偡傞         
  490. public override byte[] SequenceKeyData(Keys modifier, Keys body) {
  491. if((int)Keys.F1 <= (int)body && (int)body <= (int)Keys.F12) {
  492. byte[] r = new byte[5];
  493. r[0] = 0x1B;
  494. r[1] = (byte)'[';
  495. int n = (int)body - (int)Keys.F1;
  496. if((modifier & Keys.Shift) != Keys.None) n += 10; //shift偼抣傪10偢傜偡
  497. char tail;
  498. if(n>=20)
  499. tail = (modifier & Keys.Control) != Keys.None? '@' : '$';
  500. else
  501. tail = (modifier & Keys.Control) != Keys.None? '^' : '~';
  502. string f = FUNCTIONKEY_MAP[n];
  503. r[2] = (byte)f[0];
  504. r[3] = (byte)f[1];
  505. r[4] = (byte)tail;
  506. return r;
  507. }
  508. else if(GUtil.IsCursorKey(body)) {
  509. byte[] r = new byte[3];
  510. r[0] = 0x1B;
  511. if(_cursorKeyMode==TerminalMode.Normal)
  512. r[1] = (byte)'[';
  513. else
  514. r[1] = (byte)'O';
  515. switch(body) {
  516. case Keys.Up:
  517. r[2] = (byte)'A';
  518. break;
  519. case Keys.Down:
  520. r[2] = (byte)'B';
  521. break;
  522. case Keys.Right:
  523. r[2] = (byte)'C';
  524. break;
  525. case Keys.Left:
  526. r[2] = (byte)'D';
  527. break;
  528. default:
  529. throw new ArgumentException("unknown cursor key code", "key");
  530. }
  531. return r;
  532. }
  533. else {
  534. byte[] r = new byte[4];
  535. r[0] = 0x1B;
  536. r[1] = (byte)'[';
  537. r[3] = (byte)'~';
  538. if(body==Keys.Insert)
  539. r[2] = (byte)'1';
  540. else if(body==Keys.Home)
  541. r[2] = (byte)'2';
  542. else if(body==Keys.PageUp)
  543. r[2] = (byte)'3';
  544. else if(body==Keys.Delete)
  545. r[2] = (byte)'4';
  546. else if(body==Keys.End)
  547. r[2] = (byte)'5';
  548. else if(body==Keys.PageDown)
  549. r[2] = (byte)'6';
  550. else
  551. throw new ArgumentException("unknown key " + body.ToString());
  552. return r;
  553. }
  554. }
  555. }
  556. }