Skip to content

Commit 354896a

Browse files
mduftGerrit Code Review
authored and
Gerrit Code Review
committed
Merge "Clipboard keys fixed"
2 parents 380106f + 2c90978 commit 354896a

File tree

1 file changed

+55
-31
lines changed

1 file changed

+55
-31
lines changed

ui/webapp/src/app/modules/shared/components/file-viewer/file-viewer.component.ts

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { AfterViewInit, Component, EventEmitter, Input, OnChanges, OnDestroy, On
22
import { FormBuilder } from '@angular/forms';
33
import { NgTerminal } from 'ng-terminal';
44
import { Observable, Subscription } from 'rxjs';
5+
import { IDisposable } from 'xterm';
56
import { InstanceDirectoryEntry, StringEntryChunkDto } from '../../../../models/gen.dtos';
67
import { InstanceService } from '../../../instance/services/instance.service';
78

@@ -46,6 +47,7 @@ export class FileViewerComponent implements OnInit, AfterViewInit, OnChanges, On
4647
private offset = 0;
4748

4849
private stdinSubscription : Subscription;
50+
private resizeDisposable: IDisposable;
4951
buffer: string = '';
5052
bufferCursorPos: number = 0;
5153
initialCursorX: number; // cursor posX after terminal output (input field origin X)
@@ -59,6 +61,12 @@ export class FileViewerComponent implements OnInit, AfterViewInit, OnChanges, On
5961
}
6062

6163
ngAfterViewInit() {
64+
this.term.underlying.attachCustomKeyEventHandler(event => {
65+
// prevent default handling of Ctrl-C/Ctrl-X (otherwise it resets the selections
66+
// and default Ctrl-C/X has nothing to copy) and Ctrl-V
67+
return !event.ctrlKey || 'cxv'.indexOf(event.key.toLowerCase()) === -1;
68+
});
69+
6270
if (this.supportsStdin) {
6371
this.setupStdin(this.hasStdin);
6472
}
@@ -146,7 +154,7 @@ export class FileViewerComponent implements OnInit, AfterViewInit, OnChanges, On
146154

147155
setupStdin(connect: boolean) {
148156
if (connect) {
149-
this.term.underlying.onResize(data => {
157+
this.resizeDisposable = this.term.underlying.onResize(data => {
150158
if (this.supportsStdin && this.hasStdin && this.follow) {
151159
setTimeout(dim => {
152160
this.clearInput();
@@ -156,6 +164,7 @@ export class FileViewerComponent implements OnInit, AfterViewInit, OnChanges, On
156164
});
157165

158166
this.stdinSubscription = this.term.keyInput.subscribe(input => {
167+
// keyboard input usually is a single charactor or CSI sequence, but clipboard content is a string
159168
if (!this.follow) {
160169
return;
161170
}
@@ -164,43 +173,58 @@ export class FileViewerComponent implements OnInit, AfterViewInit, OnChanges, On
164173
this.initialCursorX = this.cursorX;
165174
}
166175

167-
if (input === '\r') {
168-
this.sendStdin();
169-
} else if (input.charCodeAt(0) === 0x7f) {
170-
if(this.bufferCursorPos > 0) {
176+
let idx = 0;
177+
while (idx < input.length) {
178+
if (input[idx] === '\r') {
179+
idx++;
180+
this.sendStdin();
181+
} else if (input.charCodeAt(idx) === 0x7f) {
182+
idx++;
183+
if(this.bufferCursorPos > 0) {
184+
this.clearInput();
185+
this.buffer = this.buffer.substring(0, this.bufferCursorPos -1) + this.buffer.substring(this.bufferCursorPos);
186+
this.bufferCursorPos--;
187+
this.updateInput();
188+
}
189+
} else {
171190
this.clearInput();
172-
this.buffer = this.buffer.substring(0, this.bufferCursorPos -1) + this.buffer.substring(this.bufferCursorPos);
173-
this.bufferCursorPos--;
174-
this.updateInput();
175-
}
176-
} else {
177-
this.clearInput();
178-
if(input.length === 1) {
179-
this.buffer = [this.buffer.slice(0, this.bufferCursorPos), input, this.buffer.slice(this.bufferCursorPos)].join('');
180-
this.bufferCursorPos++;
181-
} else if (input.startsWith(FileViewerComponent.CSI)) {
182-
const seq = input.substr(FileViewerComponent.CSI.length);
183-
switch (seq) {
184-
case 'C': // cursor right
185-
this.bufferCursorPos = this.bufferCursorPos + (this.buffer.length > this.bufferCursorPos ? 1 : 0);
186-
break;
187-
case 'D': // cursor left
188-
this.bufferCursorPos = this.bufferCursorPos - (this.bufferCursorPos > 0 ? 1 : 0);
189-
break;
190-
case 'H': // pos 1
191-
this.bufferCursorPos = 0;
192-
break;
193-
case 'F': // end
194-
this.bufferCursorPos = this.buffer.length;
195-
break;
191+
if (input.charCodeAt(idx) >= 32) {
192+
this.buffer = [this.buffer.slice(0, this.bufferCursorPos), input[idx], this.buffer.slice(this.bufferCursorPos)].join('');
193+
this.bufferCursorPos++;
194+
idx++;
195+
} else if (input.substr(idx).startsWith(FileViewerComponent.CSI)) {
196+
idx += FileViewerComponent.CSI.length;
197+
if (idx < input.length) {
198+
switch (input[idx]) {
199+
case 'C': // cursor right
200+
this.bufferCursorPos = this.bufferCursorPos + (this.buffer.length > this.bufferCursorPos ? 1 : 0);
201+
break;
202+
case 'D': // cursor left
203+
this.bufferCursorPos = this.bufferCursorPos - (this.bufferCursorPos > 0 ? 1 : 0);
204+
break;
205+
case 'H': // pos 1
206+
this.bufferCursorPos = 0;
207+
break;
208+
case 'F': // end
209+
this.bufferCursorPos = this.buffer.length;
210+
break;
211+
}
212+
idx++;
213+
}
214+
} else {
215+
// consume and ignore input character
216+
idx++;
196217
}
218+
this.updateInput();
197219
}
198-
this.updateInput();
199-
}
220+
};
221+
200222
})
201223
} else if (this.stdinSubscription) {
202224
this.stdinSubscription.unsubscribe();
203225
this.stdinSubscription = null;
226+
this.resizeDisposable.dispose();
227+
this.resizeDisposable = null;
204228
}
205229
}
206230

0 commit comments

Comments
 (0)