1fb726d48Sopenharmony_ci/*
2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb726d48Sopenharmony_ci * You may obtain a copy of the License at
6fb726d48Sopenharmony_ci *
7fb726d48Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb726d48Sopenharmony_ci *
9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and
13fb726d48Sopenharmony_ci * limitations under the License.
14fb726d48Sopenharmony_ci */
15fb726d48Sopenharmony_ci
16fb726d48Sopenharmony_ciimport { BaseElement, element } from '../../../base-ui/BaseElement';
17fb726d48Sopenharmony_ciimport { HdcDeviceManager } from '../../../hdc/HdcDeviceManager';
18fb726d48Sopenharmony_ciimport { SpRecordTrace } from '../SpRecordTrace';
19fb726d48Sopenharmony_ciimport { DataMessage } from '../../../hdc/message/DataMessage';
20fb726d48Sopenharmony_ci
21fb726d48Sopenharmony_ci@element('sp-web-hdc-shell')
22fb726d48Sopenharmony_ciexport class SpWebHdcShell extends BaseElement {
23fb726d48Sopenharmony_ci  private static MAX_DISPLAY_ROWS = 1000;
24fb726d48Sopenharmony_ci  private static MAX_SAVE_SIZE = 2097152;
25fb726d48Sopenharmony_ci  shellDiv: HTMLDivElement | null | undefined;
26fb726d48Sopenharmony_ci  currentScreenRemain: number = 0;
27fb726d48Sopenharmony_ci  private shellCanvas: HTMLCanvasElement | null | undefined;
28fb726d48Sopenharmony_ci  private shellCanvasCtx: CanvasRenderingContext2D | null | undefined;
29fb726d48Sopenharmony_ci  private resultStr = '';
30fb726d48Sopenharmony_ci  private sendCallBack: ((keyboardEvent: KeyboardEvent | string) => void | undefined) | undefined;
31fb726d48Sopenharmony_ci  private startShellDevice = '';
32fb726d48Sopenharmony_ci  private intervalId: number | undefined;
33fb726d48Sopenharmony_ci  private skipFlag: number[] = [7];
34fb726d48Sopenharmony_ci  private clearFlag: number[] = [27, 91, 50, 74, 27, 91, 72];
35fb726d48Sopenharmony_ci  private CRLFFlag: number[] = [13, 13, 10];
36fb726d48Sopenharmony_ci  private startRealTimeFlag: number[] = [27, 91, 115];
37fb726d48Sopenharmony_ci  private endRealTimeFlag: number[] = [27, 91, 117];
38fb726d48Sopenharmony_ci  private clearRealTimeFlag: number[] = [27, 91, 72, 27, 91, 74];
39fb726d48Sopenharmony_ci  private ctrlCFlag: number[] = [13, 10, 35, 32];
40fb726d48Sopenharmony_ci  private points: Point | undefined;
41fb726d48Sopenharmony_ci  private forwardFlag: boolean = false;
42fb726d48Sopenharmony_ci  private cursorIndex: number = 3;
43fb726d48Sopenharmony_ci  private shellStrLength: number = 0;
44fb726d48Sopenharmony_ci  private textY: number = 0;
45fb726d48Sopenharmony_ci  private cursorRow: string = '';
46fb726d48Sopenharmony_ci  private textDecoder: TextDecoder = new TextDecoder();
47fb726d48Sopenharmony_ci  private isDragging: boolean = false;
48fb726d48Sopenharmony_ci  private static TOP_OFFSET = 48;
49fb726d48Sopenharmony_ci  private static FIRST_ROW_OFFSET = 32;
50fb726d48Sopenharmony_ci  private static LAST_ROW_OFFSET = 40;
51fb726d48Sopenharmony_ci  private static MULTI_LINE_FLAG = '<\b';
52fb726d48Sopenharmony_ci  private static LINE_BREAK_LENGTH = 2;
53fb726d48Sopenharmony_ci  private static LEFT_OFFSET = 48;
54fb726d48Sopenharmony_ci  private realTimeResult: string | null | undefined = '';
55fb726d48Sopenharmony_ci  private startRealTime: boolean = false;
56fb726d48Sopenharmony_ci  private prevTextY: number = 0;
57fb726d48Sopenharmony_ci
58fb726d48Sopenharmony_ci  public initElements(): void {
59fb726d48Sopenharmony_ci    this.shellCanvas = this.shadowRoot!.querySelector<HTMLCanvasElement>('#shell_cmd');
60fb726d48Sopenharmony_ci    this.shellCanvasCtx = this.shellCanvas!.getContext('2d');
61fb726d48Sopenharmony_ci    this.shellCanvasCtx!.fillStyle = '#000';
62fb726d48Sopenharmony_ci
63fb726d48Sopenharmony_ci    this.shellCanvasCtx!.fillRect(0, 0, this.shellCanvas!.width, this.shellCanvas!.height);
64fb726d48Sopenharmony_ci    this.shellDiv = this.shadowRoot!.querySelector<HTMLDivElement>('.shell_cmd_div');
65fb726d48Sopenharmony_ci    this.shellCanvasAddMouseListener();
66fb726d48Sopenharmony_ci    this.shellCanvas!.addEventListener('contextmenu', (event) => {
67fb726d48Sopenharmony_ci      event.preventDefault();
68fb726d48Sopenharmony_ci      event.stopPropagation();
69fb726d48Sopenharmony_ci    });
70fb726d48Sopenharmony_ci    this.shellCanvas!.addEventListener('keydown', async (keyboardEvent) => {
71fb726d48Sopenharmony_ci      keyboardEvent.preventDefault();
72fb726d48Sopenharmony_ci      if (keyboardEvent.ctrlKey && keyboardEvent.code === 'KeyC' && this.points) {
73fb726d48Sopenharmony_ci        let rowText: string = this.getSelectedText();
74fb726d48Sopenharmony_ci        this.points = undefined;
75fb726d48Sopenharmony_ci        await navigator.clipboard.writeText(rowText);
76fb726d48Sopenharmony_ci      } else {
77fb726d48Sopenharmony_ci        if (this.sendCallBack) {
78fb726d48Sopenharmony_ci          this.sendCallBack(keyboardEvent);
79fb726d48Sopenharmony_ci        }
80fb726d48Sopenharmony_ci      }
81fb726d48Sopenharmony_ci    }); //@ts-ignore
82fb726d48Sopenharmony_ci    window.subscribe(window.SmartEvent.UI.DeviceConnect, (deviceName: string) => {
83fb726d48Sopenharmony_ci      if (deviceName) {
84fb726d48Sopenharmony_ci        this.hdcShellFocus();
85fb726d48Sopenharmony_ci      }
86fb726d48Sopenharmony_ci    });
87fb726d48Sopenharmony_ci    window.subscribe(window.SmartEvent.UI.DeviceDisConnect, () => {
88fb726d48Sopenharmony_ci      this.clear();
89fb726d48Sopenharmony_ci    });
90fb726d48Sopenharmony_ci    this.shellCanvas!.addEventListener('blur', () => {
91fb726d48Sopenharmony_ci      if (this.intervalId) {
92fb726d48Sopenharmony_ci        window.clearInterval(this.intervalId);
93fb726d48Sopenharmony_ci      }
94fb726d48Sopenharmony_ci      this.shellCanvasCtx!.clearRect(this.shellStrLength, this.textY, 12, 3);
95fb726d48Sopenharmony_ci    });
96fb726d48Sopenharmony_ci    new ResizeObserver(() => {
97fb726d48Sopenharmony_ci      this.resizeCanvas();
98fb726d48Sopenharmony_ci      this.refreshShellPage(true);
99fb726d48Sopenharmony_ci    }).observe(this);
100fb726d48Sopenharmony_ci  }
101fb726d48Sopenharmony_ci
102fb726d48Sopenharmony_ci  resizeCanvas(): void {
103fb726d48Sopenharmony_ci    if (this.shellCanvas !== null && this.shellCanvas !== undefined) {
104fb726d48Sopenharmony_ci      this.shellCanvas.width = this.shellCanvas.clientWidth;
105fb726d48Sopenharmony_ci      this.shellCanvas.height = this.shellCanvas.clientHeight;
106fb726d48Sopenharmony_ci    }
107fb726d48Sopenharmony_ci  }
108fb726d48Sopenharmony_ci
109fb726d48Sopenharmony_ci  clear(): void {
110fb726d48Sopenharmony_ci    this.sendCallBack = undefined;
111fb726d48Sopenharmony_ci    this.resultStr = '';
112fb726d48Sopenharmony_ci    this.cursorRow = '';
113fb726d48Sopenharmony_ci    this.shellCanvasCtx!.clearRect(0, 0, this.shellCanvas!.width, this.shellCanvas!.height);
114fb726d48Sopenharmony_ci    this.shellCanvasCtx!.fillStyle = '#000';
115fb726d48Sopenharmony_ci    this.shellCanvasCtx!.fillRect(0, 0, this.shellCanvas!.width, this.shellCanvas!.height);
116fb726d48Sopenharmony_ci    window.clearInterval(this.intervalId);
117fb726d48Sopenharmony_ci  }
118fb726d48Sopenharmony_ci
119fb726d48Sopenharmony_ci  public hdcShellFocus(): void {
120fb726d48Sopenharmony_ci    HdcDeviceManager.connect(SpRecordTrace.serialNumber).then((connected) => {
121fb726d48Sopenharmony_ci      if (connected) {
122fb726d48Sopenharmony_ci        if (this.sendCallBack && this.startShellDevice === SpRecordTrace.serialNumber) {
123fb726d48Sopenharmony_ci          this.shellCanvas!.focus();
124fb726d48Sopenharmony_ci          this.refreshShellPage(true);
125fb726d48Sopenharmony_ci        } else {
126fb726d48Sopenharmony_ci          this.clear();
127fb726d48Sopenharmony_ci          this.sendCallBack = HdcDeviceManager.startShell((result: DataMessage) => {
128fb726d48Sopenharmony_ci            if (result.channelClose) {
129fb726d48Sopenharmony_ci              this.clear();
130fb726d48Sopenharmony_ci              return;
131fb726d48Sopenharmony_ci            }
132fb726d48Sopenharmony_ci            this.startShellDevice = SpRecordTrace.serialNumber;
133fb726d48Sopenharmony_ci            this.handleHdcRecvData(result);
134fb726d48Sopenharmony_ci          });
135fb726d48Sopenharmony_ci          this.shellCanvas!.focus();
136fb726d48Sopenharmony_ci          this.refreshShellPage(true);
137fb726d48Sopenharmony_ci        }
138fb726d48Sopenharmony_ci      } else {
139fb726d48Sopenharmony_ci        this.clear();
140fb726d48Sopenharmony_ci      }
141fb726d48Sopenharmony_ci    });
142fb726d48Sopenharmony_ci  }
143fb726d48Sopenharmony_ci
144fb726d48Sopenharmony_ci  arrayBufferCompare(compareA: ArrayBuffer, compareB: number[]): boolean {
145fb726d48Sopenharmony_ci    const arrayA = new Uint8Array(compareA);
146fb726d48Sopenharmony_ci    if (arrayA.length === compareB.length) {
147fb726d48Sopenharmony_ci      for (let i = 0; i < arrayA.length; i++) {
148fb726d48Sopenharmony_ci        const dd = arrayA[i];
149fb726d48Sopenharmony_ci        if (dd !== compareB[i]) {
150fb726d48Sopenharmony_ci          return false;
151fb726d48Sopenharmony_ci        }
152fb726d48Sopenharmony_ci      }
153fb726d48Sopenharmony_ci      return true;
154fb726d48Sopenharmony_ci    }
155fb726d48Sopenharmony_ci    return false;
156fb726d48Sopenharmony_ci  }
157fb726d48Sopenharmony_ci
158fb726d48Sopenharmony_ci  getSelectedText(): string {
159fb726d48Sopenharmony_ci    let selectedText = '';
160fb726d48Sopenharmony_ci    let textLines = [...this.finalArr];
161fb726d48Sopenharmony_ci    let startX = this.points!.startX < SpWebHdcShell.LEFT_OFFSET ? SpWebHdcShell.LEFT_OFFSET : this.points!.startX;
162fb726d48Sopenharmony_ci    let startY = this.points!.startY;
163fb726d48Sopenharmony_ci    let endX = this.points!.endX < SpWebHdcShell.LEFT_OFFSET ? SpWebHdcShell.LEFT_OFFSET : this.points!.endX;
164fb726d48Sopenharmony_ci    let endY = this.points!.endY;
165fb726d48Sopenharmony_ci    let endTop = Math.ceil((endY - SpWebHdcShell.TOP_OFFSET) / 16);
166fb726d48Sopenharmony_ci    let startTop = Math.floor((startY - SpWebHdcShell.TOP_OFFSET - 2) / 16);
167fb726d48Sopenharmony_ci    let selectRangeList = textLines.slice(startTop + 1, endTop);
168fb726d48Sopenharmony_ci    let charWidth = this.shellCanvasCtx!.measureText(selectRangeList[0].split('')[0]).width;
169fb726d48Sopenharmony_ci    for (let index = 0; index < selectRangeList.length; index++) {
170fb726d48Sopenharmony_ci      let currentIndexLine = selectRangeList[index];
171fb726d48Sopenharmony_ci      if (index === 0) {
172fb726d48Sopenharmony_ci        let startNum = Math.floor((startX - SpWebHdcShell.LEFT_OFFSET) / charWidth);
173fb726d48Sopenharmony_ci        selectedText = currentIndexLine.slice(startNum);
174fb726d48Sopenharmony_ci      } else if (index === selectRangeList.length - 1) {
175fb726d48Sopenharmony_ci        let endNum = Math.ceil((endX - SpWebHdcShell.LEFT_OFFSET) / charWidth);
176fb726d48Sopenharmony_ci        selectedText += currentIndexLine.slice(0, endNum);
177fb726d48Sopenharmony_ci      } else {
178fb726d48Sopenharmony_ci        selectedText += `${currentIndexLine}\n`;
179fb726d48Sopenharmony_ci      }
180fb726d48Sopenharmony_ci    }
181fb726d48Sopenharmony_ci    return selectedText.trim();
182fb726d48Sopenharmony_ci  }
183fb726d48Sopenharmony_ci
184fb726d48Sopenharmony_ci  forwardSelected(startX: number, startY: number, endX: number, endY: number): void {
185fb726d48Sopenharmony_ci    //左边界x为SpWebHdcShell.LEFT_OFFSET,右边界为this.shellCanvas!.width
186fb726d48Sopenharmony_ci    let depth = Math.ceil((endY - startY) / 16);
187fb726d48Sopenharmony_ci    let startPointX = 0;
188fb726d48Sopenharmony_ci    let startPointY = 0;
189fb726d48Sopenharmony_ci    let endPointX = 0;
190fb726d48Sopenharmony_ci    let endPointY = 0;
191fb726d48Sopenharmony_ci    if (depth <= 1) {
192fb726d48Sopenharmony_ci      this.shellCanvasCtx!.fillRect(startX, startY, endX - startX, endY - startY);
193fb726d48Sopenharmony_ci      startPointX = startX;
194fb726d48Sopenharmony_ci      startPointY = startY;
195fb726d48Sopenharmony_ci      endPointX = endX;
196fb726d48Sopenharmony_ci      endPointY = endY;
197fb726d48Sopenharmony_ci    } else {
198fb726d48Sopenharmony_ci      //绘制多行
199fb726d48Sopenharmony_ci      for (let index = 1; index <= depth; index++) {
200fb726d48Sopenharmony_ci        //第一行,绘起始点到canvas右边界矩形
201fb726d48Sopenharmony_ci        if (index === 1) {
202fb726d48Sopenharmony_ci          this.shellCanvasCtx!.fillRect(startX, startY, this.shellCanvas!.width - startX, index * 16);
203fb726d48Sopenharmony_ci          startPointX = startX;
204fb726d48Sopenharmony_ci          startPointY = startY;
205fb726d48Sopenharmony_ci        } else if (index === depth) {
206fb726d48Sopenharmony_ci          //最后一行,canvas左边界到结束点矩形
207fb726d48Sopenharmony_ci          this.shellCanvasCtx!.fillRect(
208fb726d48Sopenharmony_ci            SpWebHdcShell.LEFT_OFFSET,
209fb726d48Sopenharmony_ci            startY + (index - 1) * 16,
210fb726d48Sopenharmony_ci            endX - SpWebHdcShell.LEFT_OFFSET,
211fb726d48Sopenharmony_ci            endY - (startY + (index - 1) * 16)
212fb726d48Sopenharmony_ci          );
213fb726d48Sopenharmony_ci          endPointX = endX;
214fb726d48Sopenharmony_ci          endPointY = endY;
215fb726d48Sopenharmony_ci        } else {
216fb726d48Sopenharmony_ci          //中间行,canvas的左边界到右边界的矩形
217fb726d48Sopenharmony_ci          this.shellCanvasCtx!.fillRect(
218fb726d48Sopenharmony_ci            SpWebHdcShell.LEFT_OFFSET,
219fb726d48Sopenharmony_ci            startY + (index - 1) * 16,
220fb726d48Sopenharmony_ci            this.shellCanvas!.width,
221fb726d48Sopenharmony_ci            16
222fb726d48Sopenharmony_ci          );
223fb726d48Sopenharmony_ci        }
224fb726d48Sopenharmony_ci      }
225fb726d48Sopenharmony_ci    }
226fb726d48Sopenharmony_ci    this.points = { startX: startPointX, startY: startPointY, endX: endPointX, endY: endPointY };
227fb726d48Sopenharmony_ci  }
228fb726d48Sopenharmony_ci
229fb726d48Sopenharmony_ci  getCurrentLineBackSize(currentLine: string, maxBackSize: number, isStart: boolean): number {
230fb726d48Sopenharmony_ci    let fillText = '';
231fb726d48Sopenharmony_ci    let strings = currentLine.split('');
232fb726d48Sopenharmony_ci    for (let index = 0; index < strings.length; index++) {
233fb726d48Sopenharmony_ci      let text = strings[index];
234fb726d48Sopenharmony_ci      if (
235fb726d48Sopenharmony_ci        this.shellCanvasCtx!.measureText(fillText).width < maxBackSize &&
236fb726d48Sopenharmony_ci        this.shellCanvasCtx!.measureText(fillText + text).width >= maxBackSize
237fb726d48Sopenharmony_ci      ) {
238fb726d48Sopenharmony_ci        if (!isStart) {
239fb726d48Sopenharmony_ci          fillText += text;
240fb726d48Sopenharmony_ci        }
241fb726d48Sopenharmony_ci        break;
242fb726d48Sopenharmony_ci      }
243fb726d48Sopenharmony_ci      fillText += text;
244fb726d48Sopenharmony_ci    }
245fb726d48Sopenharmony_ci    return fillText.length;
246fb726d48Sopenharmony_ci  }
247fb726d48Sopenharmony_ci
248fb726d48Sopenharmony_ci  reverseSelected(startX: number, startY: number, endX: number, endY: number): void {
249fb726d48Sopenharmony_ci    //左边界x为SpWebHdcShell.LEFT_OFFSET,右边界为this.shellCanvas!.width
250fb726d48Sopenharmony_ci    let depth = Math.ceil((startY - endY) / 16);
251fb726d48Sopenharmony_ci    let startPointX = 0;
252fb726d48Sopenharmony_ci    let startPointY = 0;
253fb726d48Sopenharmony_ci    let endPointX = 0;
254fb726d48Sopenharmony_ci    let endPointY = 0;
255fb726d48Sopenharmony_ci    if (depth <= 1) {
256fb726d48Sopenharmony_ci      this.shellCanvasCtx!.fillRect(endX, endY, startX - endX, startY - endY);
257fb726d48Sopenharmony_ci      startPointX = endX;
258fb726d48Sopenharmony_ci      startPointY = endY;
259fb726d48Sopenharmony_ci      endPointX = startX;
260fb726d48Sopenharmony_ci      endPointY = startY;
261fb726d48Sopenharmony_ci    } else {
262fb726d48Sopenharmony_ci      //绘制多行
263fb726d48Sopenharmony_ci      for (let index = 1; index <= depth; index++) {
264fb726d48Sopenharmony_ci        //第一行,绘起始点到canvas左边界矩形
265fb726d48Sopenharmony_ci        if (index === 1) {
266fb726d48Sopenharmony_ci          this.shellCanvasCtx!.fillRect(SpWebHdcShell.LEFT_OFFSET, startY - 16, startX - SpWebHdcShell.LEFT_OFFSET, 16);
267fb726d48Sopenharmony_ci          endPointX = startX;
268fb726d48Sopenharmony_ci          endPointY = startY;
269fb726d48Sopenharmony_ci        } else if (index === depth) {
270fb726d48Sopenharmony_ci          //最后一行,canvas右边界到结束点矩形
271fb726d48Sopenharmony_ci          this.shellCanvasCtx!.fillRect(endX, endY, this.shellCanvas!.width - endX, startY - (index - 1) * 16 - endY);
272fb726d48Sopenharmony_ci          startPointX = endX;
273fb726d48Sopenharmony_ci          startPointY = endY;
274fb726d48Sopenharmony_ci        } else {
275fb726d48Sopenharmony_ci          this.shellCanvasCtx!.fillRect(SpWebHdcShell.LEFT_OFFSET, startY - index * 16, this.shellCanvas!.width, 16);
276fb726d48Sopenharmony_ci          this.shellCanvasCtx!.textBaseline = 'middle';
277fb726d48Sopenharmony_ci        }
278fb726d48Sopenharmony_ci      }
279fb726d48Sopenharmony_ci    }
280fb726d48Sopenharmony_ci    this.points = { startX: startPointX, startY: startPointY, endX: endPointX, endY: endPointY };
281fb726d48Sopenharmony_ci  }
282fb726d48Sopenharmony_ci
283fb726d48Sopenharmony_ci  private singleLineToMultiLine(shellStr: string, foundationWidth: number, maxWidth: number): string[] {
284fb726d48Sopenharmony_ci    let result = [];
285fb726d48Sopenharmony_ci    while (shellStr.length * foundationWidth > maxWidth) {
286fb726d48Sopenharmony_ci      let bfb = maxWidth / (shellStr.length * foundationWidth);
287fb726d48Sopenharmony_ci      let cutIndex = Math.floor(shellStr.length * bfb);
288fb726d48Sopenharmony_ci      let ss = shellStr.substring(0, cutIndex);
289fb726d48Sopenharmony_ci      result.push(ss);
290fb726d48Sopenharmony_ci      shellStr = shellStr.substring(cutIndex);
291fb726d48Sopenharmony_ci    }
292fb726d48Sopenharmony_ci    if (shellStr.length > 0) {
293fb726d48Sopenharmony_ci      result.push(shellStr);
294fb726d48Sopenharmony_ci    }
295fb726d48Sopenharmony_ci    return result;
296fb726d48Sopenharmony_ci  }
297fb726d48Sopenharmony_ci
298fb726d48Sopenharmony_ci  private finalArr: Array<string> = [];
299fb726d48Sopenharmony_ci
300fb726d48Sopenharmony_ci  private drawShellPage(resultStrArr: string[]): void {
301fb726d48Sopenharmony_ci    let maxWidth = this.shellCanvas!.width;
302fb726d48Sopenharmony_ci    let foundationWidth = Math.ceil(this.shellCanvasCtx!.measureText(' ').width);
303fb726d48Sopenharmony_ci    for (let index = 0; index < resultStrArr.length - 1; index++) {
304fb726d48Sopenharmony_ci      let shellStr = resultStrArr[index];
305fb726d48Sopenharmony_ci      let strWidth = this.shellCanvasCtx!.measureText(shellStr).width;
306fb726d48Sopenharmony_ci      if (strWidth > maxWidth) {
307fb726d48Sopenharmony_ci        let lines = this.singleLineToMultiLine(shellStr, foundationWidth, maxWidth - SpWebHdcShell.LEFT_OFFSET);
308fb726d48Sopenharmony_ci        this.finalArr.push(...lines);
309fb726d48Sopenharmony_ci      } else {
310fb726d48Sopenharmony_ci        this.finalArr.push(shellStr);
311fb726d48Sopenharmony_ci      }
312fb726d48Sopenharmony_ci    }
313fb726d48Sopenharmony_ci    if (this.finalArr.length > SpWebHdcShell.MAX_DISPLAY_ROWS) {
314fb726d48Sopenharmony_ci      this.finalArr.splice(0, this.finalArr.length - SpWebHdcShell.MAX_DISPLAY_ROWS + 1);
315fb726d48Sopenharmony_ci    }
316fb726d48Sopenharmony_ci    this.shellCanvasCtx!.fillStyle = '#fff';
317fb726d48Sopenharmony_ci    this.shellCanvasCtx!.font = '16px serif';
318fb726d48Sopenharmony_ci    this.textY = SpWebHdcShell.TOP_OFFSET;
319fb726d48Sopenharmony_ci    this.finalArr.push(this.cursorRow);
320fb726d48Sopenharmony_ci    for (let index: number = 0; index < this.finalArr.length; index++) {
321fb726d48Sopenharmony_ci      let shellStr: string = this.finalArr[index];
322fb726d48Sopenharmony_ci      this.textY = SpWebHdcShell.TOP_OFFSET + index * 16;
323fb726d48Sopenharmony_ci      this.shellCanvasCtx!.fillText(shellStr, SpWebHdcShell.LEFT_OFFSET, this.textY);
324fb726d48Sopenharmony_ci    }
325fb726d48Sopenharmony_ci  }
326fb726d48Sopenharmony_ci
327fb726d48Sopenharmony_ci  private drawCursorStyle(): void {
328fb726d48Sopenharmony_ci    if (this.intervalId) {
329fb726d48Sopenharmony_ci      window.clearInterval(this.intervalId);
330fb726d48Sopenharmony_ci    }
331fb726d48Sopenharmony_ci    let needClear = false;
332fb726d48Sopenharmony_ci    this.intervalId = window.setInterval(() => {
333fb726d48Sopenharmony_ci      if (needClear) {
334fb726d48Sopenharmony_ci        needClear = false;
335fb726d48Sopenharmony_ci        this.shellCanvasCtx!.fillStyle = '#000';
336fb726d48Sopenharmony_ci        this.shellCanvasCtx!.fillRect(this.shellStrLength, this.textY, 12, 3);
337fb726d48Sopenharmony_ci      } else {
338fb726d48Sopenharmony_ci        needClear = true;
339fb726d48Sopenharmony_ci        this.shellCanvasCtx!.fillStyle = '#fff';
340fb726d48Sopenharmony_ci        this.shellCanvasCtx!.fillRect(this.shellStrLength, this.textY, 12, 3);
341fb726d48Sopenharmony_ci      }
342fb726d48Sopenharmony_ci    }, 500);
343fb726d48Sopenharmony_ci  }
344fb726d48Sopenharmony_ci
345fb726d48Sopenharmony_ci  refreshShellPage(scroller: boolean): void {
346fb726d48Sopenharmony_ci    try {
347fb726d48Sopenharmony_ci      if (this.resultStr.length === 0 && this.cursorRow.length === 0) {
348fb726d48Sopenharmony_ci        return;
349fb726d48Sopenharmony_ci      }
350fb726d48Sopenharmony_ci      this.shellCanvasCtx!.clearRect(0, 0, this.shellCanvas!.width, this.shellCanvas!.height);
351fb726d48Sopenharmony_ci      this.shellCanvasCtx!.fillStyle = '#000';
352fb726d48Sopenharmony_ci      this.shellCanvasCtx!.fillRect(0, 0, this.shellCanvas!.width, this.shellCanvas!.height);
353fb726d48Sopenharmony_ci      let resultStrArr = this.resultStr.split('\r\n');
354fb726d48Sopenharmony_ci      if (this.realTimeResult !== '') {
355fb726d48Sopenharmony_ci        resultStrArr = (this.resultStr + this.realTimeResult).split('\r\n');
356fb726d48Sopenharmony_ci      }
357fb726d48Sopenharmony_ci      this.finalArr = [];
358fb726d48Sopenharmony_ci      if (this.shellCanvas!.width > 0) {
359fb726d48Sopenharmony_ci        this.drawShellPage(resultStrArr);
360fb726d48Sopenharmony_ci        this.shellStrLength =
361fb726d48Sopenharmony_ci          this.shellCanvasCtx!.measureText(this.cursorRow.slice(0, this.cursorIndex)).width + SpWebHdcShell.LEFT_OFFSET;
362fb726d48Sopenharmony_ci        // 记录前一次滚动条的位置
363fb726d48Sopenharmony_ci        this.prevTextY = this.shellDiv!.scrollTop + this.shellDiv!.clientHeight - 3;
364fb726d48Sopenharmony_ci        if (scroller && this.textY > this.shellDiv!.clientHeight && this.textY > this.prevTextY) {
365fb726d48Sopenharmony_ci          this.shellDiv!.scrollTop = this.textY - this.shellDiv!.clientHeight + 3;
366fb726d48Sopenharmony_ci          this.currentScreenRemain = this.shellDiv!.scrollTop;
367fb726d48Sopenharmony_ci        }
368fb726d48Sopenharmony_ci        this.drawCursorStyle();
369fb726d48Sopenharmony_ci      }
370fb726d48Sopenharmony_ci    } catch (e) { }
371fb726d48Sopenharmony_ci  }
372fb726d48Sopenharmony_ci
373fb726d48Sopenharmony_ci  public initHtml(): string {
374fb726d48Sopenharmony_ci    return `
375fb726d48Sopenharmony_ci    <style>
376fb726d48Sopenharmony_ci    :host{
377fb726d48Sopenharmony_ci        display: block;
378fb726d48Sopenharmony_ci        border-radius: 0 16px 16px 0;
379fb726d48Sopenharmony_ci        width: 100%;
380fb726d48Sopenharmony_ci        position: relative;
381fb726d48Sopenharmony_ci    }
382fb726d48Sopenharmony_ci    .shell_cmd_div {
383fb726d48Sopenharmony_ci        width: 90%;
384fb726d48Sopenharmony_ci        margin-left: 5%;
385fb726d48Sopenharmony_ci        margin-top: 3%;
386fb726d48Sopenharmony_ci        overflow-y: scroll;
387fb726d48Sopenharmony_ci        height: 40rem;
388fb726d48Sopenharmony_ci        background: #000;
389fb726d48Sopenharmony_ci        border: 1px solid var(--dark-color1,#4D4D4D);
390fb726d48Sopenharmony_ci        border-radius: 16px;
391fb726d48Sopenharmony_ci    }
392fb726d48Sopenharmony_ci     ::-webkit-scrollbar{
393fb726d48Sopenharmony_ci       width: 13px;
394fb726d48Sopenharmony_ci       height: 10px;
395fb726d48Sopenharmony_ci       background-color: #FFFFFF;
396fb726d48Sopenharmony_ci     }
397fb726d48Sopenharmony_ci     ::-webkit-scrollbar-track{
398fb726d48Sopenharmony_ci       border-top-right-radius: 16px;
399fb726d48Sopenharmony_ci       border-bottom-right-radius: 16px;
400fb726d48Sopenharmony_ci       background-color: #000000;
401fb726d48Sopenharmony_ci     }
402fb726d48Sopenharmony_ci     ::-webkit-scrollbar-thumb{
403fb726d48Sopenharmony_ci       background: #5A5A5A;
404fb726d48Sopenharmony_ci       border-radius: 6px;
405fb726d48Sopenharmony_ci     }
406fb726d48Sopenharmony_ci    canvas {
407fb726d48Sopenharmony_ci         display: inline-block;
408fb726d48Sopenharmony_ci         outline: none;
409fb726d48Sopenharmony_ci    }
410fb726d48Sopenharmony_ci
411fb726d48Sopenharmony_ci    </style>
412fb726d48Sopenharmony_ci    <div class="shell_cmd_div">
413fb726d48Sopenharmony_ci        <canvas id="shell_cmd" style="width: 100%;height:${16000 + SpWebHdcShell.TOP_OFFSET}px;" tabindex="0"></canvas>
414fb726d48Sopenharmony_ci    </div>
415fb726d48Sopenharmony_ci    `;
416fb726d48Sopenharmony_ci  }
417fb726d48Sopenharmony_ci
418fb726d48Sopenharmony_ci  private refreshCurrentRow(): void {
419fb726d48Sopenharmony_ci    let lastRow: string = this.resultStr;
420fb726d48Sopenharmony_ci    if (this.resultStr.lastIndexOf('\r\n') !== -1) {
421fb726d48Sopenharmony_ci      lastRow = this.resultStr.substring(this.resultStr.lastIndexOf('\r\n') + 2);
422fb726d48Sopenharmony_ci    }
423fb726d48Sopenharmony_ci    let currentRow: string[] = [...lastRow];
424fb726d48Sopenharmony_ci    let result: string[] = [];
425fb726d48Sopenharmony_ci    this.cursorIndex = 0;
426fb726d48Sopenharmony_ci    for (let index: number = 0; index < currentRow.length; index++) {
427fb726d48Sopenharmony_ci      let currentResult: string = currentRow[index];
428fb726d48Sopenharmony_ci      if (currentResult === '\b') {
429fb726d48Sopenharmony_ci        this.cursorIndex--;
430fb726d48Sopenharmony_ci      } else {
431fb726d48Sopenharmony_ci        result[this.cursorIndex] = currentResult;
432fb726d48Sopenharmony_ci        this.cursorIndex++;
433fb726d48Sopenharmony_ci      }
434fb726d48Sopenharmony_ci    }
435fb726d48Sopenharmony_ci    this.cursorRow = result.join('');
436fb726d48Sopenharmony_ci  }
437fb726d48Sopenharmony_ci
438fb726d48Sopenharmony_ci  private handleHdcRecvData(result: DataMessage): void {
439fb726d48Sopenharmony_ci    const resData = result.getData();
440fb726d48Sopenharmony_ci    if (resData) {
441fb726d48Sopenharmony_ci      if (this.arrayBufferCompare(resData, this.skipFlag)) {
442fb726d48Sopenharmony_ci        return;
443fb726d48Sopenharmony_ci      } else if (this.arrayBufferCompare(resData, this.clearFlag)) {
444fb726d48Sopenharmony_ci        this.resultStr = '';
445fb726d48Sopenharmony_ci        this.shellDiv!.scrollTop = 0;
446fb726d48Sopenharmony_ci        this.cursorIndex = 3;
447fb726d48Sopenharmony_ci      } else if (this.arrayBufferCompare(resData, this.CRLFFlag)) {
448fb726d48Sopenharmony_ci        if (this.resultStr.lastIndexOf('\r\n') !== -1) {
449fb726d48Sopenharmony_ci          this.resultStr = this.resultStr.substring(0, this.resultStr.lastIndexOf('\r\n') + 2) + this.cursorRow;
450fb726d48Sopenharmony_ci        } else {
451fb726d48Sopenharmony_ci          this.resultStr = this.cursorRow;
452fb726d48Sopenharmony_ci        }
453fb726d48Sopenharmony_ci        this.resultStr += result.getDataToString();
454fb726d48Sopenharmony_ci        this.cursorIndex = 3;
455fb726d48Sopenharmony_ci      } else {
456fb726d48Sopenharmony_ci        if (this.resultStr.length > SpWebHdcShell.MAX_SAVE_SIZE) {
457fb726d48Sopenharmony_ci          this.resultStr = this.resultStr.substring(this.resultStr.length / 2);
458fb726d48Sopenharmony_ci        }
459fb726d48Sopenharmony_ci        const arrayA = new Uint8Array(resData);
460fb726d48Sopenharmony_ci        if (arrayA[0] === 13 && arrayA[1] !== 10 && arrayA[1] !== 13) {
461fb726d48Sopenharmony_ci          this.hdcRecvEnterAndBracket(arrayA, result);
462fb726d48Sopenharmony_ci        } else if (this.isStartWidthArrayBuffer(arrayA, this.startRealTimeFlag)) {
463fb726d48Sopenharmony_ci          let lastIndex = this.getLastRestorationIndex(arrayA, this.endRealTimeFlag);
464fb726d48Sopenharmony_ci          this.realTimeResult = this.removeTextAndColorSequenceStr(
465fb726d48Sopenharmony_ci            this.textDecoder.decode(arrayA.slice(lastIndex, arrayA.length))
466fb726d48Sopenharmony_ci          );
467fb726d48Sopenharmony_ci          this.startRealTime = true;
468fb726d48Sopenharmony_ci        } else if (this.isStartWidthArrayBuffer(arrayA, this.clearRealTimeFlag)) {
469fb726d48Sopenharmony_ci          this.realTimeResult = this.removeTextAndColorSequenceStr(
470fb726d48Sopenharmony_ci            this.textDecoder.decode(arrayA.slice(6, arrayA.length))
471fb726d48Sopenharmony_ci          );
472fb726d48Sopenharmony_ci          this.startRealTime = true;
473fb726d48Sopenharmony_ci        } else {
474fb726d48Sopenharmony_ci          if (this.isStartWidthArrayBuffer(arrayA, this.ctrlCFlag)) {
475fb726d48Sopenharmony_ci            this.resultStr += this.realTimeResult;
476fb726d48Sopenharmony_ci            this.startRealTime = false;
477fb726d48Sopenharmony_ci          }
478fb726d48Sopenharmony_ci          this.hdcRecvRealMessage(result);
479fb726d48Sopenharmony_ci        }
480fb726d48Sopenharmony_ci      }
481fb726d48Sopenharmony_ci      this.resultStr = this.removeTextAndColorSequenceStr(this.resultStr);
482fb726d48Sopenharmony_ci      this.refreshCurrentRow();
483fb726d48Sopenharmony_ci      this.refreshShellPage(true);
484fb726d48Sopenharmony_ci    }
485fb726d48Sopenharmony_ci  }
486fb726d48Sopenharmony_ci
487fb726d48Sopenharmony_ci  private hdcRecvEnterAndBracket(arrayA: Uint8Array, result: DataMessage): void {
488fb726d48Sopenharmony_ci    const index = this.resultStr.lastIndexOf('\n');
489fb726d48Sopenharmony_ci    const resultStrLength = this.resultStr.length;
490fb726d48Sopenharmony_ci    if (index > -1 && resultStrLength > index) {
491fb726d48Sopenharmony_ci      this.resultStr = this.resultStr.substring(0, index + 1) + this.textDecoder.decode(arrayA.slice(1, arrayA.length));
492fb726d48Sopenharmony_ci    } else {
493fb726d48Sopenharmony_ci      if (this.resultStr.split('\n').length === 1) {
494fb726d48Sopenharmony_ci        const index = this.cursorRow.lastIndexOf('\n');
495fb726d48Sopenharmony_ci        this.cursorRow =
496fb726d48Sopenharmony_ci          this.cursorRow.substring(0, index + 1) + this.textDecoder.decode(arrayA.slice(1, arrayA.length));
497fb726d48Sopenharmony_ci        this.resultStr = this.cursorRow;
498fb726d48Sopenharmony_ci      } else {
499fb726d48Sopenharmony_ci        this.resultStr += result.getDataToString();
500fb726d48Sopenharmony_ci      }
501fb726d48Sopenharmony_ci    }
502fb726d48Sopenharmony_ci    this.realTimeResult = '';
503fb726d48Sopenharmony_ci  }
504fb726d48Sopenharmony_ci
505fb726d48Sopenharmony_ci  private hdcRecvRealMessage(result: DataMessage): void {
506fb726d48Sopenharmony_ci    if (this.startRealTime) {
507fb726d48Sopenharmony_ci      if (result.getDataToString().includes(SpWebHdcShell.MULTI_LINE_FLAG)) {
508fb726d48Sopenharmony_ci        this.realTimeResult += result.getDataToString().substring(result.getDataToString().indexOf('\r'));
509fb726d48Sopenharmony_ci      } else {
510fb726d48Sopenharmony_ci        this.realTimeResult += result.getDataToString();
511fb726d48Sopenharmony_ci      }
512fb726d48Sopenharmony_ci      this.realTimeResult = this.removeTextAndColorSequenceStr(this.realTimeResult!);
513fb726d48Sopenharmony_ci    } else {
514fb726d48Sopenharmony_ci      this.realTimeResult = '';
515fb726d48Sopenharmony_ci      if (result.getDataToString().includes(SpWebHdcShell.MULTI_LINE_FLAG)) {
516fb726d48Sopenharmony_ci        // 获取所有内容,不包括最后一行数据
517fb726d48Sopenharmony_ci        this.resultStr = this.resultStr.substring(
518fb726d48Sopenharmony_ci          0,
519fb726d48Sopenharmony_ci          this.resultStr.lastIndexOf('\r\n') + SpWebHdcShell.LINE_BREAK_LENGTH
520fb726d48Sopenharmony_ci        );
521fb726d48Sopenharmony_ci        // 多行情况不能直接拼接返回数据
522fb726d48Sopenharmony_ci        this.resultStr += result.getDataToString().substring(result.getDataToString().indexOf('\r'));
523fb726d48Sopenharmony_ci      } else {
524fb726d48Sopenharmony_ci        this.resultStr += result.getDataToString();
525fb726d48Sopenharmony_ci      }
526fb726d48Sopenharmony_ci    }
527fb726d48Sopenharmony_ci  }
528fb726d48Sopenharmony_ci
529fb726d48Sopenharmony_ci  private removeTextAndColorSequenceStr(currentStr: string): string {
530fb726d48Sopenharmony_ci    return currentStr.replace(new RegExp(/\x1B\[[0-9;]*[a-zA-Z]/g), '');
531fb726d48Sopenharmony_ci  }
532fb726d48Sopenharmony_ci
533fb726d48Sopenharmony_ci  private isStartWidthArrayBuffer(sourceArray: Uint8Array, compareArray: number[]): boolean {
534fb726d48Sopenharmony_ci    for (let index = 0; index < compareArray.length; index++) {
535fb726d48Sopenharmony_ci      if (sourceArray[index] !== compareArray[index]) {
536fb726d48Sopenharmony_ci        return false;
537fb726d48Sopenharmony_ci      }
538fb726d48Sopenharmony_ci    }
539fb726d48Sopenharmony_ci    return true;
540fb726d48Sopenharmony_ci  }
541fb726d48Sopenharmony_ci
542fb726d48Sopenharmony_ci  private getLastRestorationIndex(sourceArray: Uint8Array, compareArray: number[]): number {
543fb726d48Sopenharmony_ci    let lastIndex = -1;
544fb726d48Sopenharmony_ci    for (let index = sourceArray.length - 1; index >= 0; index--) {
545fb726d48Sopenharmony_ci      if (sourceArray[index] === compareArray[0]) {
546fb726d48Sopenharmony_ci        let isLast = true;
547fb726d48Sopenharmony_ci        for (let j = 1; j < compareArray.length; j++) {
548fb726d48Sopenharmony_ci          if (sourceArray[index + j] !== compareArray[j]) {
549fb726d48Sopenharmony_ci            isLast = false;
550fb726d48Sopenharmony_ci            break;
551fb726d48Sopenharmony_ci          }
552fb726d48Sopenharmony_ci        }
553fb726d48Sopenharmony_ci        if (isLast) {
554fb726d48Sopenharmony_ci          lastIndex = index;
555fb726d48Sopenharmony_ci          break;
556fb726d48Sopenharmony_ci        }
557fb726d48Sopenharmony_ci      }
558fb726d48Sopenharmony_ci    }
559fb726d48Sopenharmony_ci    return lastIndex + compareArray.length;
560fb726d48Sopenharmony_ci  }
561fb726d48Sopenharmony_ci
562fb726d48Sopenharmony_ci  private shellCanvasAddMouseListener(): void {
563fb726d48Sopenharmony_ci    let startX: number;
564fb726d48Sopenharmony_ci    let startY: number;
565fb726d48Sopenharmony_ci    let endX: number;
566fb726d48Sopenharmony_ci    let endY: number;
567fb726d48Sopenharmony_ci    this.shellCanvas!.addEventListener('mousedown', (event) => {
568fb726d48Sopenharmony_ci      if (this.resultStr.length === 0 && this.cursorRow.length === 0) {
569fb726d48Sopenharmony_ci        return;
570fb726d48Sopenharmony_ci      }
571fb726d48Sopenharmony_ci      this.isDragging = true;
572fb726d48Sopenharmony_ci      startX = event.offsetX;
573fb726d48Sopenharmony_ci      startY = event.offsetY;
574fb726d48Sopenharmony_ci      this.refreshShellPage(false);
575fb726d48Sopenharmony_ci    });
576fb726d48Sopenharmony_ci    this.shellCanvas!.addEventListener('mousemove', (event) => {
577fb726d48Sopenharmony_ci      if (!this.isDragging) {
578fb726d48Sopenharmony_ci        return;
579fb726d48Sopenharmony_ci      }
580fb726d48Sopenharmony_ci      if (this.resultStr.length === 0 && this.cursorRow.length === 0) {
581fb726d48Sopenharmony_ci        return;
582fb726d48Sopenharmony_ci      }
583fb726d48Sopenharmony_ci      endX = event.offsetX;
584fb726d48Sopenharmony_ci      endY = event.offsetY;
585fb726d48Sopenharmony_ci      this.refreshShellPage(false);
586fb726d48Sopenharmony_ci      this.points = undefined;
587fb726d48Sopenharmony_ci      this.shellCanvasCtx!.fillStyle = 'rgba(128, 128, 128, 0.5)';
588fb726d48Sopenharmony_ci      if (endY > startY) {
589fb726d48Sopenharmony_ci        this.forwardFlag = true;
590fb726d48Sopenharmony_ci        this.forwardSelected(startX, startY, endX, endY);
591fb726d48Sopenharmony_ci      } else {
592fb726d48Sopenharmony_ci        this.forwardFlag = false;
593fb726d48Sopenharmony_ci        this.reverseSelected(startX, startY, endX, endY);
594fb726d48Sopenharmony_ci      }
595fb726d48Sopenharmony_ci    });
596fb726d48Sopenharmony_ci    this.shellCanvasAddMouseUpListener();
597fb726d48Sopenharmony_ci  }
598fb726d48Sopenharmony_ci
599fb726d48Sopenharmony_ci  private shellCanvasAddMouseUpListener(): void {
600fb726d48Sopenharmony_ci    this.shellCanvas!.addEventListener('mouseup', async (event)=> {
601fb726d48Sopenharmony_ci      if (!this.isDragging) {
602fb726d48Sopenharmony_ci        return;
603fb726d48Sopenharmony_ci      }
604fb726d48Sopenharmony_ci      if (this.resultStr.length === 0 && this.cursorRow.length === 0) {
605fb726d48Sopenharmony_ci        return;
606fb726d48Sopenharmony_ci      }
607fb726d48Sopenharmony_ci      this.isDragging = false;
608fb726d48Sopenharmony_ci      //右键
609fb726d48Sopenharmony_ci      if (event.button === 2) {
610fb726d48Sopenharmony_ci        let text: string = await navigator.clipboard.readText();
611fb726d48Sopenharmony_ci        if (text) {
612fb726d48Sopenharmony_ci          if (this.sendCallBack) {
613fb726d48Sopenharmony_ci            this.sendCallBack(text);
614fb726d48Sopenharmony_ci          }
615fb726d48Sopenharmony_ci          return;
616fb726d48Sopenharmony_ci        }
617fb726d48Sopenharmony_ci      }
618fb726d48Sopenharmony_ci    });
619fb726d48Sopenharmony_ci  }
620fb726d48Sopenharmony_ci}
621fb726d48Sopenharmony_ci
622fb726d48Sopenharmony_ciexport class Point {
623fb726d48Sopenharmony_ci  startX: number = 0;
624fb726d48Sopenharmony_ci  startY: number = 0;
625fb726d48Sopenharmony_ci  endX: number = 0;
626fb726d48Sopenharmony_ci  endY: number = 0;
627fb726d48Sopenharmony_ci}
628