From 4e1be7c1a3e589d7b804a1e617cb8a086b25a909 Mon Sep 17 00:00:00 2001 From: Dariusz L Date: Wed, 23 Jul 2025 17:05:19 +0200 Subject: [PATCH] Reset key states on window blur in CanvasInteractions Adds a window blur event listener to reset key states and interaction modes when the window loses focus. This prevents stuck key states and finalizes any in-progress cloning drags, improving interaction reliability. --- js/CanvasInteractions.js | 19 +++++++++++++++++++ src/CanvasInteractions.ts | 23 +++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/js/CanvasInteractions.js b/js/CanvasInteractions.js index b794d66..64a7396 100644 --- a/js/CanvasInteractions.js +++ b/js/CanvasInteractions.js @@ -31,6 +31,8 @@ export class CanvasInteractions { this.canvas.canvas.addEventListener('wheel', this.handleWheel.bind(this), { passive: false }); this.canvas.canvas.addEventListener('keydown', this.handleKeyDown.bind(this)); this.canvas.canvas.addEventListener('keyup', this.handleKeyUp.bind(this)); + // Add a blur event listener to the window to reset key states + window.addEventListener('blur', this.handleBlur.bind(this)); document.addEventListener('paste', this.handlePasteEvent.bind(this)); this.canvas.canvas.addEventListener('mouseenter', (e) => { this.canvas.isMouseOver = true; @@ -373,6 +375,23 @@ export class CanvasInteractions { this.interaction.keyMovementInProgress = false; } } + handleBlur() { + log.debug('Window lost focus, resetting key states.'); + this.interaction.isCtrlPressed = false; + this.interaction.isAltPressed = false; + this.interaction.keyMovementInProgress = false; + // Also reset any interaction that relies on a key being held down + if (this.interaction.mode === 'dragging' && this.interaction.hasClonedInDrag) { + // If we were in the middle of a cloning drag, finalize it + this.canvas.saveState(); + this.canvas.canvasState.saveStateToDB(); + } + // Reset interaction mode if it's something that can get "stuck" + if (this.interaction.mode !== 'none' && this.interaction.mode !== 'drawingMask') { + this.resetInteractionState(); + this.canvas.render(); + } + } updateCursor(worldCoords) { const transformTarget = this.canvas.canvasLayers.getHandleAtPosition(worldCoords.x, worldCoords.y); if (transformTarget) { diff --git a/src/CanvasInteractions.ts b/src/CanvasInteractions.ts index 832ce6f..1262d53 100644 --- a/src/CanvasInteractions.ts +++ b/src/CanvasInteractions.ts @@ -59,6 +59,9 @@ export class CanvasInteractions { this.canvas.canvas.addEventListener('keydown', this.handleKeyDown.bind(this) as EventListener); this.canvas.canvas.addEventListener('keyup', this.handleKeyUp.bind(this) as EventListener); + // Add a blur event listener to the window to reset key states + window.addEventListener('blur', this.handleBlur.bind(this)); + document.addEventListener('paste', this.handlePasteEvent.bind(this)); this.canvas.canvas.addEventListener('mouseenter', (e: MouseEvent) => { @@ -426,6 +429,26 @@ export class CanvasInteractions { } } + handleBlur(): void { + log.debug('Window lost focus, resetting key states.'); + this.interaction.isCtrlPressed = false; + this.interaction.isAltPressed = false; + this.interaction.keyMovementInProgress = false; + + // Also reset any interaction that relies on a key being held down + if (this.interaction.mode === 'dragging' && this.interaction.hasClonedInDrag) { + // If we were in the middle of a cloning drag, finalize it + this.canvas.saveState(); + this.canvas.canvasState.saveStateToDB(); + } + + // Reset interaction mode if it's something that can get "stuck" + if (this.interaction.mode !== 'none' && this.interaction.mode !== 'drawingMask') { + this.resetInteractionState(); + this.canvas.render(); + } + } + updateCursor(worldCoords: Point): void { const transformTarget = this.canvas.canvasLayers.getHandleAtPosition(worldCoords.x, worldCoords.y);