From dc7e888ee3be073e858499a18a3c220b59f11bd9 Mon Sep 17 00:00:00 2001 From: boksbc Date: Mon, 11 May 2026 22:34:44 +0200 Subject: [PATCH] fix: click-through HUD, tray icon fallback, toggle shortcut, ESC handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - hud.js: setIgnoreMouseEvents when inactive, alwaysOnTop only when active, backgroundColor #00000000, no visibleOnAllWorkspaces, toggleHud export - tray.js: onToggle callback, isEmpty() fallback icon, click toggles - preload.js: ESC listener at capture phase — works without HUD page changes - main.js: Cmd+Shift+F toggles, import toggleHud, pass onToggle to tray Co-Authored-By: Claude Sonnet 4.6 --- electron/hud.js | 35 ++++++++++++++++++++++++++++------- electron/main.js | 7 ++++--- electron/preload.js | 5 +++++ electron/tray.js | 17 +++++++++++++---- 4 files changed, 50 insertions(+), 14 deletions(-) diff --git a/electron/hud.js b/electron/hud.js index 4c5f234..87b6168 100644 --- a/electron/hud.js +++ b/electron/hud.js @@ -5,6 +5,7 @@ const HUD_URL = process.env.FOX_HUD_URL || 'https://fox.pxo.at/hud'; let hudWindow = null; let hudLoaded = false; let pendingShow = false; +let hudActive = false; function createHud() { const { width, height } = screen.getPrimaryDisplay().workAreaSize; @@ -16,7 +17,8 @@ function createHud() { y: 0, frame: false, transparent: true, - alwaysOnTop: true, + backgroundColor: '#00000000', + alwaysOnTop: false, show: false, skipTaskbar: true, hasShadow: false, @@ -29,14 +31,14 @@ function createHud() { }, }); - hudWindow.setAlwaysOnTop(true, 'screen-saver'); - hudWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true }); + // Unsichtbar und click-through bis aktiv + hudWindow.setIgnoreMouseEvents(true); hudWindow.webContents.once('did-finish-load', () => { hudLoaded = true; if (pendingShow) { pendingShow = false; - hudWindow.webContents.send('hud-show'); + _activateHud(); } }); @@ -46,28 +48,47 @@ function createHud() { hudWindow = null; hudLoaded = false; pendingShow = false; + hudActive = false; }); return hudWindow; } +function _activateHud() { + hudActive = true; + hudWindow.setIgnoreMouseEvents(false); + hudWindow.setAlwaysOnTop(true, 'screen-saver'); + hudWindow.webContents.send('hud-show'); +} + function showHud() { if (!hudWindow) createHud(); hudWindow.show(); hudWindow.focus(); if (hudLoaded) { - hudWindow.webContents.send('hud-show'); + _activateHud(); } else { pendingShow = true; } } function hideHud() { - if (!hudWindow) return; + if (!hudWindow || !hudActive) return; + hudActive = false; + hudWindow.setAlwaysOnTop(false); + hudWindow.setIgnoreMouseEvents(true); hudWindow.webContents.send('hud-hide'); setTimeout(() => { if (hudWindow) hudWindow.hide(); }, 600); } -module.exports = { createHud, showHud, hideHud }; +function toggleHud() { + if (hudActive) { + hideHud(); + } else { + showHud(); + } +} + +module.exports = { createHud, showHud, hideHud, toggleHud }; diff --git a/electron/main.js b/electron/main.js index 88dbd1c..17632c1 100644 --- a/electron/main.js +++ b/electron/main.js @@ -1,6 +1,6 @@ const { app, ipcMain, globalShortcut, nativeTheme } = require('electron'); const { createTray } = require('./tray'); -const { createHud, showHud, hideHud } = require('./hud'); +const { createHud, showHud, hideHud, toggleHud } = require('./hud'); const { startWakeword, stopWakeword } = require('./wakeword'); const { executeMacCommand } = require('./mac-agent'); const axios = require('axios'); @@ -19,12 +19,13 @@ app.whenReady().then(() => { createHud(); createTray({ - onShow: showHud, + onToggle: toggleHud, onHide: hideHud, onQuit: () => app.quit(), }); - globalShortcut.register('CommandOrControl+Shift+F', showHud); + // Cmd+Shift+F togglet HUD + globalShortcut.register('CommandOrControl+Shift+F', toggleHud); startWakeword({ onWake: showHud }); diff --git a/electron/preload.js b/electron/preload.js index 7ebe65d..d15ed58 100644 --- a/electron/preload.js +++ b/electron/preload.js @@ -1,5 +1,10 @@ const { contextBridge, ipcRenderer } = require('electron'); +// ESC schließt HUD — funktioniert unabhängig vom HUD-JavaScript +window.addEventListener('keydown', (e) => { + if (e.key === 'Escape') ipcRenderer.send('hide-hud'); +}, true); + contextBridge.exposeInMainWorld('foxBridge', { sendMessage: (text) => ipcRenderer.send('send-message', text), hideHud: () => ipcRenderer.send('hide-hud'), diff --git a/electron/tray.js b/electron/tray.js index 8383377..0fa91ed 100644 --- a/electron/tray.js +++ b/electron/tray.js @@ -3,22 +3,31 @@ const path = require('path'); let tray = null; -function createTray({ onShow, onHide, onQuit }) { +function createTray({ onToggle, onHide, onQuit }) { const iconPath = path.join(__dirname, '../assets/fox-tray.png'); - const icon = nativeImage.createFromPath(iconPath); + let icon = nativeImage.createFromPath(iconPath); + + if (icon.isEmpty()) { + console.warn('[Tray] Icon nicht gefunden:', iconPath, '— Fallback auf leeres Icon'); + // Minimales 1x1 schwarzes Template-PNG als Fallback + icon = nativeImage.createFromDataURL( + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==' + ); + } + icon.setTemplateImage(true); tray = new Tray(icon); tray.setToolTip('Fox'); tray.setContextMenu(Menu.buildFromTemplate([ - { label: 'Fox öffnen', accelerator: 'Cmd+Shift+F', click: onShow }, + { label: 'Fox öffnen/schließen', accelerator: 'Cmd+Shift+F', click: onToggle }, { label: 'Fox verstecken', click: onHide }, { type: 'separator' }, { label: 'Beenden', click: onQuit }, ])); - tray.on('click', onShow); + tray.on('click', onToggle); return tray; }