mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
handle non-running terminal keypresses
This commit is contained in:
+2
-5
@@ -12,6 +12,7 @@ import {TermWrap} from "./term";
|
||||
import type {SessionDataType, LineType, CmdDataType, RemoteType, RemoteStateType, RemoteInstanceType, RemotePtrType, HistoryItem, HistoryQueryOpts, RemoteEditType} from "./types";
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||
import {GlobalModel, GlobalCommandRunner, Session, Cmd, Window, Screen, ScreenWindow, riToRPtr, widthToCols, termWidthFromCols, termHeightFromRows} from "./model";
|
||||
import {isModKeyPress} from "./util";
|
||||
|
||||
dayjs.extend(localizedFormat)
|
||||
|
||||
@@ -439,10 +440,6 @@ class TextAreaInput extends React.Component<{}, {}> {
|
||||
}
|
||||
}
|
||||
|
||||
isModKeyPress(e : any) {
|
||||
return e.code.match(/^(Control|Meta|Alt|Shift)(Left|Right)$/);
|
||||
}
|
||||
|
||||
getLinePos(elem : any) : {numLines : number, linePos : number} {
|
||||
let numLines = elem.value.split("\n").length;
|
||||
let linePos = elem.value.substr(0, elem.selectionStart).split("\n").length;
|
||||
@@ -452,7 +449,7 @@ class TextAreaInput extends React.Component<{}, {}> {
|
||||
@mobx.action @boundMethod
|
||||
onKeyDown(e : any) {
|
||||
mobx.action(() => {
|
||||
if (this.isModKeyPress(e)) {
|
||||
if (isModKeyPress(e)) {
|
||||
return;
|
||||
}
|
||||
let model = GlobalModel;
|
||||
|
||||
+51
-11
@@ -2,7 +2,7 @@ import * as mobx from "mobx";
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {boundMethod} from "autobind-decorator";
|
||||
import {debounce} from "throttle-debounce";
|
||||
import {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, boundInt} from "./util";
|
||||
import {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, boundInt, isModKeyPress} from "./util";
|
||||
import {TermWrap} from "./term";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
import type {SessionDataType, WindowDataType, LineType, RemoteType, HistoryItem, RemoteInstanceType, RemotePtrType, CmdDataType, FeCmdPacketType, TermOptsType, RemoteStateType, ScreenDataType, ScreenWindowType, ScreenOptsType, LayoutType, PtyDataUpdateType, ModelUpdateType, UpdateMessage, InfoType, CmdLineUpdateType, UIContextType, HistoryInfoType, HistoryQueryOpts, FeInputPacketType, TermWinSize, RemoteInputPacketType} from "./types";
|
||||
@@ -171,7 +171,8 @@ class Cmd {
|
||||
return cmdStatusIsRunning(data.status);
|
||||
}
|
||||
|
||||
handleKey(event : any) {
|
||||
handleData(data : string, termWrap : TermWrap) : void {
|
||||
console.log("handle data", {data: data});
|
||||
if (!this.isRunning()) {
|
||||
return;
|
||||
}
|
||||
@@ -179,7 +180,7 @@ class Cmd {
|
||||
type: "feinput",
|
||||
ck: this.sessionId + "/" + this.cmdId,
|
||||
remote: this.remote,
|
||||
inputdata64: btoa(event.key),
|
||||
inputdata64: btoa(data),
|
||||
};
|
||||
GlobalModel.sendInputPacket(inputPacket);
|
||||
}
|
||||
@@ -460,6 +461,33 @@ class ScreenWindow {
|
||||
}
|
||||
}
|
||||
|
||||
termCustomKeyHandlerInternal(e : any, termWrap : TermWrap) : void {
|
||||
if (e.code == "ArrowUp") {
|
||||
termWrap.terminal.scrollLines(-1);
|
||||
return;
|
||||
}
|
||||
if (e.code == "ArrowDown") {
|
||||
termWrap.terminal.scrollLines(1);
|
||||
return;
|
||||
}
|
||||
if (e.code == "PageUp") {
|
||||
termWrap.terminal.scrollPages(-1);
|
||||
return;
|
||||
}
|
||||
if (e.code == "PageDown") {
|
||||
termWrap.terminal.scrollPages(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
termCustomKeyHandler(e : any, termWrap : TermWrap) : boolean {
|
||||
if (e.type != "keydown" || isModKeyPress(e)) {
|
||||
return termWrap.isRunning;
|
||||
}
|
||||
this.termCustomKeyHandlerInternal(e, termWrap);
|
||||
return termWrap.isRunning;
|
||||
}
|
||||
|
||||
connectElem(elem : Element, line : LineType, cmd : Cmd, width : number) {
|
||||
let cmdId = cmd.cmdId;
|
||||
let termWrap = this.getTermWrap(cmdId);
|
||||
@@ -469,9 +497,16 @@ class ScreenWindow {
|
||||
}
|
||||
let cols = widthToCols(width);
|
||||
let usedRows = GlobalModel.getTUR(this.sessionId, cmdId, cols);
|
||||
termWrap = new TermWrap(
|
||||
elem, {sessionId: this.sessionId, cmdId: cmdId}, usedRows, cmd.getTermOpts(), {height: 0, width: width},
|
||||
cmd.handleKey.bind(cmd), (focus : boolean) => this.setTermFocus(line.linenum, focus), cmd.isRunning());
|
||||
termWrap = new TermWrap(elem, {
|
||||
termContext: {sessionId: this.sessionId, cmdId: cmdId},
|
||||
usedRows: usedRows,
|
||||
termOpts: cmd.getTermOpts(),
|
||||
winSize: {height: 0, width: width},
|
||||
dataHandler: cmd.handleData.bind(cmd),
|
||||
focusHandler: (focus : boolean) => this.setTermFocus(line.linenum, focus),
|
||||
isRunning: cmd.isRunning(),
|
||||
customKeyHandler: this.termCustomKeyHandler.bind(this),
|
||||
});
|
||||
this.terms[cmdId] = termWrap;
|
||||
if ((this.focusType.get() == "cmd" || this.focusType.get() == "cmd-fg") && this.selectedLine.get() == line.linenum) {
|
||||
termWrap.focusTerminal();
|
||||
@@ -1331,7 +1366,7 @@ class InputModel {
|
||||
})();
|
||||
}
|
||||
|
||||
termKeyHandler(remoteId : string, event : any) : void {
|
||||
termKeyHandler(remoteId : string, event : any, termWrap : TermWrap) : void {
|
||||
let remote = GlobalModel.getRemote(remoteId);
|
||||
if (remote == null) {
|
||||
return;
|
||||
@@ -1366,10 +1401,15 @@ class InputModel {
|
||||
}
|
||||
else {
|
||||
let termOpts = {rows: RemotePtyRows, cols: RemotePtyCols, flexrows: false, maxptysize: 64*1024};
|
||||
this.remoteTermWrap = new TermWrap(
|
||||
elem, {remoteId: remoteId}, RemotePtyRows, termOpts, null,
|
||||
(e) => { this.termKeyHandler(remoteId, e)},
|
||||
this.setRemoteTermWrapFocus.bind(this), true);
|
||||
this.remoteTermWrap = new TermWrap(elem, {
|
||||
termContext: {remoteId: remoteId},
|
||||
usedRows: RemotePtyRows,
|
||||
termOpts: termOpts,
|
||||
winSize: null,
|
||||
keyHandler: (e, termWrap) => { this.termKeyHandler(remoteId, e, termWrap)},
|
||||
focusHandler: this.setRemoteTermWrapFocus.bind(this),
|
||||
isRunning: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-15
@@ -22,6 +22,18 @@ const MaxTermCols = 1024;
|
||||
|
||||
type TermContext = {sessionId? : string, cmdId? : string, remoteId? : string};
|
||||
|
||||
type TermWrapOpts = {
|
||||
termContext : TermContext,
|
||||
usedRows? : number,
|
||||
termOpts : TermOptsType,
|
||||
winSize : WindowSize,
|
||||
keyHandler? : (event : any, termWrap : TermWrap) => void,
|
||||
focusHandler? : (focus : boolean) => void,
|
||||
dataHandler? : (data : string, termWrap : TermWrap) => void,
|
||||
isRunning : boolean,
|
||||
customKeyHandler? : (event : any, termWrap : TermWrap) => boolean,
|
||||
};
|
||||
|
||||
// cmd-instance
|
||||
class TermWrap {
|
||||
terminal : any;
|
||||
@@ -40,27 +52,28 @@ class TermWrap {
|
||||
focusHandler : (focus : boolean) => void;
|
||||
isRunning : boolean;
|
||||
|
||||
constructor(elem : Element, termContext : TermContext, usedRows : number, termOpts : TermOptsType, winSize : WindowSize, keyHandler : (event : any) => void, focusHandler : (focus : boolean) => void, isRunning : boolean) {
|
||||
this.termContext = termContext;
|
||||
constructor(elem : Element, opts : TermWrapOpts) {
|
||||
opts = opts ?? ({} as any);
|
||||
this.termContext = opts.termContext;
|
||||
this.connectedElem = elem;
|
||||
this.flexRows = termOpts.flexrows ?? false;
|
||||
this.winSize = winSize;
|
||||
this.focusHandler = focusHandler;
|
||||
this.isRunning = isRunning;
|
||||
this.flexRows = opts.termOpts.flexrows ?? false;
|
||||
this.winSize = opts.winSize;
|
||||
this.focusHandler = opts.focusHandler;
|
||||
this.isRunning = opts.isRunning;
|
||||
if (this.flexRows) {
|
||||
this.atRowMax = false;
|
||||
this.usedRows = mobx.observable.box(usedRows ?? (isRunning ? 2 : 0));
|
||||
this.usedRows = mobx.observable.box(opts.usedRows ?? (opts.isRunning ? 2 : 0));
|
||||
}
|
||||
else {
|
||||
this.atRowMax = true;
|
||||
this.usedRows = mobx.observable.box(termOpts.rows);
|
||||
this.usedRows = mobx.observable.box(opts.termOpts.rows);
|
||||
}
|
||||
if (winSize == null) {
|
||||
this.termSize = {rows: termOpts.rows, cols: termOpts.cols};
|
||||
if (opts.winSize == null) {
|
||||
this.termSize = {rows: opts.termOpts.rows, cols: opts.termOpts.cols};
|
||||
}
|
||||
else {
|
||||
let cols = widthToCols(winSize.width);
|
||||
this.termSize = {rows: termOpts.rows, cols: cols};
|
||||
let cols = widthToCols(opts.winSize.width);
|
||||
this.termSize = {rows: opts.termOpts.rows, cols: cols};
|
||||
}
|
||||
let theme = {
|
||||
foreground: "#d3d7cf",
|
||||
@@ -71,8 +84,11 @@ class TermWrap {
|
||||
return state;
|
||||
});
|
||||
this.terminal.open(elem);
|
||||
if (keyHandler != null) {
|
||||
this.terminal.onKey(keyHandler);
|
||||
if (opts.keyHandler != null) {
|
||||
this.terminal.onKey((e) => opts.keyHandler(e, this));
|
||||
}
|
||||
if (opts.dataHandler != null) {
|
||||
this.terminal.onData((e) => opts.dataHandler(e, this));
|
||||
}
|
||||
this.terminal.textarea.addEventListener("focus", () => {
|
||||
if (this.focusHandler != null) {
|
||||
@@ -88,6 +104,9 @@ class TermWrap {
|
||||
}
|
||||
});
|
||||
elem.addEventListener("scroll", this.elemScrollHandler);
|
||||
if (opts.customKeyHandler != null) {
|
||||
this.terminal.attachCustomKeyEventHandler((e) => opts.customKeyHandler(e, this));
|
||||
}
|
||||
this.reloadTerminal(0);
|
||||
}
|
||||
|
||||
@@ -97,7 +116,8 @@ class TermWrap {
|
||||
// xterm.js renders a textarea that handles focus. when it focuses and a space is typed the browser
|
||||
// will scroll to make it visible (even though our terminal element has overflow hidden)
|
||||
// this will undo that scroll.
|
||||
if (e.target.scrollTop == 0) {
|
||||
console.log("scroll", this.atRowMax, e.target.scrollTop);
|
||||
if (this.atRowMax || e.target.scrollTop == 0) {
|
||||
return;
|
||||
}
|
||||
e.target.scrollTop = 0;
|
||||
|
||||
+5
-1
@@ -172,4 +172,8 @@ function boundInt(ival : number, minVal : number, maxVal : number) : number {
|
||||
return ival;
|
||||
}
|
||||
|
||||
export {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, parseEnv0, boundInt};
|
||||
function isModKeyPress(e : any) {
|
||||
return e.code.match(/^(Control|Meta|Alt|Shift)(Left|Right)$/);
|
||||
}
|
||||
|
||||
export {handleJsonFetchResponse, base64ToArray, genMergeData, genMergeSimpleData, parseEnv0, boundInt, isModKeyPress};
|
||||
|
||||
Reference in New Issue
Block a user