From a75e21138e44e86105ec03e228e212570e390fbd Mon Sep 17 00:00:00 2001 From: Vantz Stockwell Date: Mon, 16 Mar 2026 12:49:30 -0400 Subject: [PATCH] fix: RDP keyboard capture yields to form elements in modals and toolbars Keyboard events now check if focus is on an input, textarea, select, or contenteditable element and let the browser handle them normally. Also fixes connectRdp type (Awaited<>) and async onMounted in RdpCanvas. Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/components/rdp/RdpCanvas.vue | 6 +++--- frontend/composables/useRdp.ts | 24 +++++++++++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/frontend/components/rdp/RdpCanvas.vue b/frontend/components/rdp/RdpCanvas.vue index 4ba0cbc..4814c7e 100644 --- a/frontend/components/rdp/RdpCanvas.vue +++ b/frontend/components/rdp/RdpCanvas.vue @@ -12,7 +12,7 @@ const props = defineProps<{ const container = ref(null) const { connectRdp } = useRdp() -let rdpSession: ReturnType['connectRdp']> | null = null +let rdpSession: Awaited['connectRdp']>> | null = null // Expose to parent (RdpToolbar uses these) const sendClipboard = (text: string) => rdpSession?.sendClipboardText(text) @@ -20,10 +20,10 @@ const disconnect = () => rdpSession?.disconnect() defineExpose({ sendClipboard, disconnect }) -onMounted(() => { +onMounted(async () => { if (!container.value) return - rdpSession = connectRdp( + rdpSession = await connectRdp( container.value, props.hostId, props.hostName, diff --git a/frontend/composables/useRdp.ts b/frontend/composables/useRdp.ts index 5e3aaa5..5fcb300 100644 --- a/frontend/composables/useRdp.ts +++ b/frontend/composables/useRdp.ts @@ -237,10 +237,28 @@ export function useRdp() { }, ) - // Keyboard input + // Keyboard input — attached to document for global capture, but yield to + // form elements (inputs, textareas, selects, contenteditable) so modals, + // toolbars, and other UI overlays can receive keystrokes normally. const keyboard = new Guacamole.Keyboard(document) - keyboard.onkeydown = (keysym: number) => client.sendKeyEvent(1, keysym) - keyboard.onkeyup = (keysym: number) => client.sendKeyEvent(0, keysym) + + function isTypingInFormElement(): boolean { + const el = document.activeElement as HTMLElement | null + if (!el) return false + const tag = el.tagName + return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || el.isContentEditable + } + + keyboard.onkeydown = (keysym: number) => { + if (isTypingInFormElement()) return true // let browser handle it + client.sendKeyEvent(1, keysym) + return false + } + keyboard.onkeyup = (keysym: number) => { + if (isTypingInFormElement()) return true + client.sendKeyEvent(0, keysym) + return false + } // Initiate the WebSocket connection client.connect()