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