mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-15 04:43:36 +00:00
feat: add ctrl+alt+delete button for rdp/vnc sessions
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
import React, { useState, useEffect, useCallback } from "react";
|
import React, { useState, useEffect, useRef, useCallback } from "react";
|
||||||
import { GuacamoleDisplay } from "@/features/guacamole/GuacamoleDisplay.tsx";
|
import {
|
||||||
|
GuacamoleDisplay,
|
||||||
|
type GuacamoleDisplayHandle,
|
||||||
|
} from "@/features/guacamole/GuacamoleDisplay.tsx";
|
||||||
import { FullScreenAppWrapper } from "@/features/FullScreenAppWrapper.tsx";
|
import { FullScreenAppWrapper } from "@/features/FullScreenAppWrapper.tsx";
|
||||||
import { getGuacamoleTokenFromHost } from "@/main-axios.ts";
|
import { getGuacamoleTokenFromHost } from "@/main-axios.ts";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { AlertCircle, RefreshCw } from "lucide-react";
|
import { AlertCircle, RefreshCw, Keyboard } from "lucide-react";
|
||||||
import { Button } from "@/components/button.tsx";
|
import { Button } from "@/components/button.tsx";
|
||||||
import { SimpleLoader } from "@/lib/SimpleLoader.tsx";
|
import { SimpleLoader } from "@/lib/SimpleLoader.tsx";
|
||||||
import type { SSHHost } from "@/types";
|
import type { SSHHost } from "@/types";
|
||||||
@@ -71,6 +74,7 @@ const GuacamoleAppInner: React.FC<GuacamoleAppInnerProps> = ({
|
|||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [connectionError, setConnectionError] = useState<string | null>(null);
|
const [connectionError, setConnectionError] = useState<string | null>(null);
|
||||||
const [retryCount, setRetryCount] = useState(0);
|
const [retryCount, setRetryCount] = useState(0);
|
||||||
|
const displayRef = useRef<GuacamoleDisplayHandle>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setToken(null);
|
setToken(null);
|
||||||
@@ -87,6 +91,18 @@ const GuacamoleAppInner: React.FC<GuacamoleAppInnerProps> = ({
|
|||||||
setRetryCount((c) => c + 1);
|
setRetryCount((c) => c + 1);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const sendCtrlAltDelete = useCallback(() => {
|
||||||
|
const display = displayRef.current;
|
||||||
|
if (!display) return;
|
||||||
|
// keysyms: Control_L=0xffe3, Alt_L=0xffe9, Delete=0xffff
|
||||||
|
display.sendKey(0xffe3, true);
|
||||||
|
display.sendKey(0xffe9, true);
|
||||||
|
display.sendKey(0xffff, true);
|
||||||
|
display.sendKey(0xffff, false);
|
||||||
|
display.sendKey(0xffe9, false);
|
||||||
|
display.sendKey(0xffe3, false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -162,10 +178,21 @@ const GuacamoleAppInner: React.FC<GuacamoleAppInnerProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<GuacamoleDisplay
|
<GuacamoleDisplay
|
||||||
|
ref={displayRef}
|
||||||
connectionConfig={{ token, protocol, type: protocol }}
|
connectionConfig={{ token, protocol, type: protocol }}
|
||||||
isVisible={true}
|
isVisible={true}
|
||||||
onError={(err) => setConnectionError(err)}
|
onError={(err) => setConnectionError(err)}
|
||||||
/>
|
/>
|
||||||
|
{(protocol === "rdp" || protocol === "vnc") && (
|
||||||
|
<button
|
||||||
|
onClick={sendCtrlAltDelete}
|
||||||
|
title="Ctrl+Alt+Delete"
|
||||||
|
className="absolute top-3 right-3 z-10 flex items-center gap-1.5 px-2.5 py-1.5 text-[10px] font-semibold uppercase tracking-wider bg-background/80 backdrop-blur border border-border rounded hover:bg-muted transition-colors opacity-60 hover:opacity-100"
|
||||||
|
>
|
||||||
|
<Keyboard className="size-3" />
|
||||||
|
Ctrl+Alt+Del
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user