parent
bd04b91e3e
commit
1a64ada0c3
2 changed files with 105 additions and 108 deletions
@ -1,122 +1,107 @@ |
|||||||
import { useEffect, useRef, memo } from 'react'; |
import { useEffect, useRef, MutableRefObject, memo } from 'react'; |
||||||
import { RFB } from 'novnc-node'; |
import RFB from './noVNC/core/rfb'; |
||||||
|
|
||||||
type VncProps = { |
type Props = { |
||||||
rfb: typeof RFB; |
rfb: MutableRefObject<RFB | undefined>; |
||||||
// The URL for the VNC connection: protocol, host, port, and path.
|
|
||||||
url: string; |
url: string; |
||||||
|
style: { width: string; height: string }; |
||||||
// Define width and height via style or separate props
|
viewOnly: boolean; |
||||||
style?: { width: number | string; height: number | string }; |
focusOnClick: boolean; |
||||||
width?: number | string; |
clipViewport: boolean; |
||||||
height?: number | string; |
dragViewport: boolean; |
||||||
|
scaleViewport: boolean; |
||||||
// Force a URL to be communicated with as encrypted.
|
resizeSession: boolean; |
||||||
encrypt?: boolean; |
showDotCursor: boolean; |
||||||
|
background: string; |
||||||
// List of WebSocket protocols this connection should support.
|
qualityLevel: number; |
||||||
wsProtocols?: string[]; |
compressionLevel: number; |
||||||
|
|
||||||
// VNC connection changes.
|
|
||||||
onUpdateState?: () => void; |
|
||||||
|
|
||||||
onPasswordRequired?: () => void; |
|
||||||
|
|
||||||
// Alert is raised on the VNC connection.
|
|
||||||
onBell?: () => void; |
|
||||||
|
|
||||||
// The desktop name is entered for the connection.
|
|
||||||
onDesktopName?: () => void; |
|
||||||
|
|
||||||
connectTimeout?: number; |
|
||||||
|
|
||||||
disconnectTimeout?: number; |
|
||||||
|
|
||||||
// A VNC connection should disconnect other connections before connecting.
|
|
||||||
shared?: boolean; |
|
||||||
|
|
||||||
trueColor?: boolean; |
|
||||||
localCursor?: boolean; |
|
||||||
}; |
}; |
||||||
|
|
||||||
const VncDisplay = ({ |
const VncDisplay = (props: Props): JSX.Element => { |
||||||
|
const screen = useRef<HTMLDivElement>(null); |
||||||
|
|
||||||
|
const { |
||||||
rfb, |
rfb, |
||||||
style, |
|
||||||
url, |
url, |
||||||
encrypt, |
|
||||||
...opts |
|
||||||
}: VncProps): JSX.Element => { |
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null); |
|
||||||
|
|
||||||
/* eslint-disable no-param-reassign */ |
|
||||||
useEffect(() => { |
|
||||||
if (!rfb.current) |
|
||||||
rfb.current = new RFB({ |
|
||||||
...opts, |
|
||||||
style, |
style, |
||||||
encrypt: encrypt !== null ? encrypt : url.startsWith('wss:'), |
viewOnly, |
||||||
target: canvasRef.current, |
focusOnClick, |
||||||
}); |
clipViewport, |
||||||
|
dragViewport, |
||||||
if (!rfb.current) return; |
scaleViewport, |
||||||
|
resizeSession, |
||||||
|
showDotCursor, |
||||||
|
background, |
||||||
|
qualityLevel, |
||||||
|
compressionLevel, |
||||||
|
} = props; |
||||||
|
|
||||||
if (!canvasRef.current) { |
useEffect(() => { |
||||||
/* eslint-disable consistent-return */ |
if (!screen.current) { |
||||||
return (): void => { |
return (): void => { |
||||||
rfb.current.disconnect(); |
if (rfb.current) { |
||||||
|
rfb?.current.disconnect(); |
||||||
rfb.current = undefined; |
rfb.current = undefined; |
||||||
|
} |
||||||
}; |
}; |
||||||
} |
} |
||||||
|
|
||||||
rfb.current.connect(url); |
if (!rfb.current) { |
||||||
|
screen.current.innerHTML = ''; |
||||||
|
|
||||||
|
rfb.current = new RFB(screen.current, url); |
||||||
|
|
||||||
|
rfb.current.viewOnly = viewOnly; |
||||||
|
rfb.current.focusOnClick = focusOnClick; |
||||||
|
rfb.current.clipViewport = clipViewport; |
||||||
|
rfb.current.dragViewport = dragViewport; |
||||||
|
rfb.current.resizeSession = resizeSession; |
||||||
|
rfb.current.scaleViewport = scaleViewport; |
||||||
|
rfb.current.showDotCursor = showDotCursor; |
||||||
|
rfb.current.background = background; |
||||||
|
rfb.current.qualityLevel = qualityLevel; |
||||||
|
rfb.current.compressionLevel = compressionLevel; |
||||||
|
} |
||||||
|
|
||||||
|
/* eslint-disable consistent-return */ |
||||||
|
if (!rfb.current) return; |
||||||
|
|
||||||
return (): void => { |
return (): void => { |
||||||
|
if (rfb.current) { |
||||||
rfb.current.disconnect(); |
rfb.current.disconnect(); |
||||||
rfb.current = undefined; |
rfb.current = undefined; |
||||||
|
} |
||||||
}; |
}; |
||||||
}, [rfb, encrypt, opts, url, style]); |
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [rfb]); |
||||||
|
|
||||||
const handleMouseEnter = () => { |
const handleMouseEnter = () => { |
||||||
if (!rfb.current) return; |
if ( |
||||||
if (document.activeElement) (document.activeElement as HTMLElement).blur(); |
document.activeElement && |
||||||
rfb.current.get_keyboard().grab(); |
document.activeElement instanceof HTMLElement |
||||||
rfb.current.get_mouse().grab(); |
) { |
||||||
|
document.activeElement.blur(); |
||||||
|
} |
||||||
|
|
||||||
|
if (rfb?.current) { |
||||||
|
rfb.current.focus(); |
||||||
|
} |
||||||
}; |
}; |
||||||
|
|
||||||
const handleMouseLeave = () => { |
const handleMouseLeave = () => { |
||||||
if (!rfb.current) return; |
if (rfb?.current) { |
||||||
|
rfb.current.blur(); |
||||||
rfb.current.get_keyboard().ungrab(); |
} |
||||||
rfb.current.get_mouse().ungrab(); |
|
||||||
}; |
}; |
||||||
|
|
||||||
return ( |
return ( |
||||||
<canvas |
<div |
||||||
style={style} |
style={style} |
||||||
ref={canvasRef} |
ref={screen} |
||||||
onMouseEnter={handleMouseEnter} |
onMouseEnter={handleMouseEnter} |
||||||
onMouseLeave={handleMouseLeave} |
onMouseLeave={handleMouseLeave} |
||||||
/> |
/> |
||||||
); |
); |
||||||
}; |
}; |
||||||
|
|
||||||
VncDisplay.defaultProps = { |
export default memo(VncDisplay); |
||||||
style: null, |
|
||||||
encrypt: null, |
|
||||||
wsProtocols: ['binary'], |
|
||||||
trueColor: true, |
|
||||||
localCursor: true, |
|
||||||
connectTimeout: 5, |
|
||||||
disconnectTimeout: 5, |
|
||||||
width: 1280, |
|
||||||
height: 720, |
|
||||||
onUpdateState: null, |
|
||||||
onPasswordRequired: null, |
|
||||||
onBell: null, |
|
||||||
onDesktopName: null, |
|
||||||
shared: false, |
|
||||||
}; |
|
||||||
|
|
||||||
const MemoVncDisplay = memo(VncDisplay); |
|
||||||
|
|
||||||
export default MemoVncDisplay; |
|
||||||
|
Loading…
Reference in new issue