From 12b8b6ed7deacf9c73c6618f5ba4af8da5084839 Mon Sep 17 00:00:00 2001 From: Taksh Date: Wed, 24 Jun 2026 17:54:42 +0530 Subject: [PATCH] Fix keyboard events dropped after UI focus changes Only skip forwarding keydown events from text inputs and contentEditable elements instead of blocking all non-document targets. Fixes key-sensing blocks stopping after selecting a sprite in the sprite list. Addresses the same root cause as scratchfoundation/scratch-gui#10047. Co-authored-by: Cursor --- packages/scratch-gui/src/lib/vm-listener-hoc.jsx | 11 +++-------- .../test/unit/util/vm-listener-hoc.test.jsx | 11 ++++------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/packages/scratch-gui/src/lib/vm-listener-hoc.jsx b/packages/scratch-gui/src/lib/vm-listener-hoc.jsx index 1400651dcc5..db1208bbcd1 100644 --- a/packages/scratch-gui/src/lib/vm-listener-hoc.jsx +++ b/packages/scratch-gui/src/lib/vm-listener-hoc.jsx @@ -98,14 +98,9 @@ const vmListenerHOC = function (WrappedComponent) { } } handleKeyDown (e) { - // Don't capture keys intended for HTML inputs (e.g. project title). - // The Blockly workspace is rendered as SVG, so SVG-targeted events - // should always reach the VM for key-sensing — even when a block has - // Blockly focus — so that game controls are never silently dropped - // while the user is on the Code tab. - if (e.target !== document && e.target !== document.body) { - if (!(e.target instanceof SVGElement)) return; - } + // Don't capture keys intended for Blockly inputs. + if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement || + e.target.isContentEditable) return; const key = (!e.key || e.key === 'Dead') ? e.keyCode : e.key; this.props.vm.postIOData('keyboard', { diff --git a/packages/scratch-gui/test/unit/util/vm-listener-hoc.test.jsx b/packages/scratch-gui/test/unit/util/vm-listener-hoc.test.jsx index 4fd40669738..4a71911dfaf 100644 --- a/packages/scratch-gui/test/unit/util/vm-listener-hoc.test.jsx +++ b/packages/scratch-gui/test/unit/util/vm-listener-hoc.test.jsx @@ -168,15 +168,12 @@ describe('VMListenerHOC', () => { /> ); - // keydown with an HTML target (e.g. project title input) should not be forwarded to VM - const inputEl = document.createElement('input'); - eventTriggers.keydown({key: 'A', target: inputEl}); + // keyboard events in text inputs are ignored + eventTriggers.keydown({key: 'A', target: document.createElement('input')}); expect(vm.postIOData).not.toHaveBeenLastCalledWith('keyboard', {key: 'A', isDown: true}); - // keydown with an SVG target (Blockly workspace) should always be forwarded to VM - // even when a block has Blockly focus, so game controls work from the Code tab - const svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - eventTriggers.keydown({key: 'A', target: svgEl}); + // keydown with other non-input targets are sent to the vm via postIOData + eventTriggers.keydown({key: 'A', target: document.createElement('div')}); expect(vm.postIOData).toHaveBeenLastCalledWith('keyboard', {key: 'A', isDown: true}); // keydown/up with target as the document are sent to the vm via postIOData