diff --git a/src/app/common/elements/inlinesettingstextedit.tsx b/src/app/common/elements/inlinesettingstextedit.tsx index d6cf9497b..539e24177 100644 --- a/src/app/common/elements/inlinesettingstextedit.tsx +++ b/src/app/common/elements/inlinesettingstextedit.tsx @@ -8,6 +8,8 @@ import { boundMethod } from "autobind-decorator"; import cn from "classnames"; import { If } from "tsx-control-statements/components"; import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil"; +import { GlobalModel } from "@/models"; +import { v4 as uuidv4 } from "uuid"; import "./inlinesettingstextedit.less"; @@ -27,6 +29,11 @@ class InlineSettingsTextEdit extends React.Component< tempText: OV; shouldFocus: boolean = false; inputRef: React.RefObject = React.createRef(); + curId: string; + + componentDidMount(): void { + this.curId = uuidv4(); + } componentDidUpdate(): void { if (this.shouldFocus) { @@ -52,6 +59,7 @@ class InlineSettingsTextEdit extends React.Component< this.tempText = null; this.props.onChange(newText); })(); + this.unregisterKeybindings(); } @boundMethod @@ -60,24 +68,38 @@ class InlineSettingsTextEdit extends React.Component< this.isEditing.set(false); this.tempText = null; })(); + this.unregisterKeybindings(); } - @boundMethod - handleKeyDown(e: any): void { - let waveEvent = adaptFromReactOrNativeKeyEvent(e); - if (checkKeyPressed(waveEvent, "Enter")) { - e.preventDefault(); - e.stopPropagation(); + handleFocus() { + this.registerKeybindings(); + } + + registerKeybindings() { + let keybindManager = GlobalModel.keybindManager; + let domain = "inline-settings" + this.curId; + keybindManager.registerKeybinding("mainview", domain, "generic:confirm", (waveEvent) => { this.confirmChange(); - return; - } - if (checkKeyPressed(waveEvent, "Escape")) { - e.preventDefault(); - e.stopPropagation(); + return true; + }); + keybindManager.registerKeybinding("mainview", domain, "generic:cancel", (waveEvent) => { this.cancelChange(); - return; - } - return; + return true; + }); + } + + unregisterKeybindings() { + let domain = "inline-settings" + this.curId; + GlobalModel.keybindManager.unregisterDomain(domain); + } + + handleBlur() { + this.unregisterKeybindings(); + this.cancelChange(); + } + + componentWillUnmount(): void { + this.unregisterKeybindings(); } @boundMethod @@ -99,7 +121,8 @@ class InlineSettingsTextEdit extends React.Component< ref={this.inputRef} className="input" type="text" - onKeyDown={this.handleKeyDown} + onFocus={this.handleFocus.bind(this)} + onBlur={this.handleBlur.bind(this)} placeholder={this.props.placeholder} onChange={this.handleChangeText} value={this.tempText.get()} diff --git a/src/app/common/elements/modal.tsx b/src/app/common/elements/modal.tsx index 187992a69..a8bfec5fe 100644 --- a/src/app/common/elements/modal.tsx +++ b/src/app/common/elements/modal.tsx @@ -6,8 +6,11 @@ import * as mobx from "mobx"; import { If } from "tsx-control-statements/components"; import ReactDOM from "react-dom"; import { Button } from "./button"; +import { v4 as uuidv4 } from "uuid"; +import { GlobalModel } from "@/models"; import "./modal.less"; +import { boundMethod } from "autobind-decorator"; interface ModalHeaderProps { onClose?: () => void; @@ -30,10 +33,52 @@ interface ModalFooterProps { onOk?: () => void; cancelLabel?: string; okLabel?: string; + keybindings?: boolean; } -const ModalFooter: React.FC = ({ onCancel, onOk, cancelLabel = "Cancel", okLabel = "Ok" }) => ( +class ModalKeybindings extends React.Component<{ onOk; onCancel }, {}> { + curId: string; + + @boundMethod + componentDidMount(): void { + this.curId = uuidv4(); + let domain = "modal-" + this.curId; + let keybindManager = GlobalModel.keybindManager; + if (this.props.onOk) { + keybindManager.registerKeybinding("modal", domain, "generic:confirm", (waveEvent) => { + this.props.onOk(); + return true; + }); + } + if (this.props.onCancel) { + keybindManager.registerKeybinding("modal", domain, "generic:cancel", (waveEvent) => { + this.props.onCancel(); + return true; + }); + } + } + + @boundMethod + componentWillUnmount(): void { + GlobalModel.keybindManager.unregisterDomain("modal-" + this.curId); + } + + render(): React.ReactNode { + return null; + } +} + +const ModalFooter: React.FC = ({ + onCancel, + onOk, + cancelLabel = "Cancel", + okLabel = "Ok", + keybindings = true, +}) => (
+ + + {onCancel && (
+ @@ -62,6 +64,7 @@ class AlertModal extends React.Component<{}, {}> { + diff --git a/src/app/common/modals/userinput.tsx b/src/app/common/modals/userinput.tsx index 035163dd0..6a9d5139f 100644 --- a/src/app/common/modals/userinput.tsx +++ b/src/app/common/modals/userinput.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { GlobalModel } from "@/models"; import { Choose, When, If } from "tsx-control-statements/components"; import { Modal, PasswordField, TextField, Markdown, Checkbox } from "@/elements"; -import { checkKeyPressed, adaptFromReactOrNativeKeyEvent } from "@/util/keyutil"; +import { checkKeyPressed, adaptFromReactOrNativeKeyEvent, KeybindManager } from "@/util/keyutil"; import "./userinput.less"; @@ -44,17 +44,20 @@ export const UserInputModal = (userInputRequest: UserInputRequest) => { [userInputRequest] ); - function handleTextKeyDown(e: React.KeyboardEvent) { - let waveEvent = adaptFromReactOrNativeKeyEvent(e); - if (checkKeyPressed(waveEvent, "Enter")) { - e.preventDefault(); - e.stopPropagation(); + function handleTextFocus() { + let keybindManager = GlobalModel.keybindManager; + keybindManager.registerKeybinding("modal", "userinput", "generic:confirm", (waveEvent) => { handleSendText(); - } else if (checkKeyPressed(waveEvent, "Escape")) { - e.preventDefault(); - e.stopPropagation(); + return true; + }); + keybindManager.registerKeybinding("modal", "userinput", "generic:cancel", (waveEvent) => { handleSendCancel(); - } + return true; + }); + } + + function handleTextBlur() { + GlobalModel.keybindManager.unregisterDomain("userinput"); } React.useEffect(() => { @@ -89,7 +92,8 @@ export const UserInputModal = (userInputRequest: UserInputRequest) => { value={responseText} maxLength={400} autoFocus={true} - onKeyDown={(e) => handleTextKeyDown(e)} + onFocus={() => handleTextFocus()} + onBlur={() => handleTextBlur()} /> @@ -98,7 +102,8 @@ export const UserInputModal = (userInputRequest: UserInputRequest) => { value={responseText} maxLength={400} autoFocus={true} - onKeyDown={(e) => handleTextKeyDown(e)} + onFocus={() => handleTextFocus()} + onBlur={() => handleTextBlur()} /> diff --git a/src/app/common/modals/viewremoteconndetail.tsx b/src/app/common/modals/viewremoteconndetail.tsx index 36a14120d..b3f1a08b0 100644 --- a/src/app/common/modals/viewremoteconndetail.tsx +++ b/src/app/common/modals/viewremoteconndetail.tsx @@ -14,6 +14,7 @@ import * as textmeasure from "@/util/textmeasure"; import * as appconst from "@/app/appconst"; import "./viewremoteconndetail.less"; +import { ModalKeybindings } from "../elements/modal"; @mobxReact.observer class ViewRemoteConnDetailModal extends React.Component<{}, {}> { @@ -382,6 +383,20 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
+ { + if (selectedRemoteStatus == "connecting") { + return; + } + this.handleClose(); + }} + onCancel={() => { + if (selectedRemoteStatus == "connecting") { + return; + } + this.handleClose(); + }} + >