From 8a2b7ee5e9646099d900991a4f91aba9e5d64588 Mon Sep 17 00:00:00 2001 From: Andrew Zambazos Date: Sun, 28 Dec 2025 10:35:59 +1300 Subject: [PATCH] Enhance Big Picture Mode OSK and webview input support Adds native input event injection for webviews via IPC, improves the on-screen keyboard (OSK) UI with a blinking cursor and label, and enables seamless text entry into webview input fields. Also refines virtual cursor click handling for better compatibility with complex sites and video players. --- main.js | 16 ++ preload.js | 5 +- renderer/bigpicture.css | 78 ++++++- renderer/bigpicture.html | 10 +- renderer/bigpicture.js | 461 +++++++++++++++++++++++++++++++++++---- 5 files changed, 513 insertions(+), 57 deletions(-) diff --git a/main.js b/main.js index 54841ee..2dbfa55 100644 --- a/main.js +++ b/main.js @@ -204,6 +204,22 @@ ipcMain.on('exit-bigpicture', () => { exitBigPictureMode(); }); +// IPC handler for sending mouse input events to webviews (used by Big Picture Mode) +ipcMain.handle('webview-send-input-event', async (event, { webContentsId, inputEvent }) => { + try { + const { webContents: webContentsModule } = require('electron'); + const targetWebContents = webContentsModule.fromId(webContentsId); + if (targetWebContents && !targetWebContents.isDestroyed()) { + targetWebContents.sendInputEvent(inputEvent); + return { success: true }; + } + return { success: false, error: 'WebContents not found' }; + } catch (err) { + console.error('[Main] webview-send-input-event error:', err); + return { success: false, error: err.message }; + } +}); + // ============================================================================= diff --git a/preload.js b/preload.js index 39b7e78..855fc00 100644 --- a/preload.js +++ b/preload.js @@ -127,7 +127,10 @@ contextBridge.exposeInMainWorld('bigPictureAPI', { // Exit Big Picture Mode exit: () => ipcRenderer.invoke('exit-bigpicture'), // Navigate to URL (from Big Picture Mode) - navigate: (url) => ipcRenderer.send('bigpicture-navigate', url) + navigate: (url) => ipcRenderer.send('bigpicture-navigate', url), + // Send input event to a webview (for virtual cursor clicks) + sendInputEvent: (webContentsId, inputEvent) => + ipcRenderer.invoke('webview-send-input-event', { webContentsId, inputEvent }) }); // Relay context-menu commands from main to active renderer context (open new tabs etc.) diff --git a/renderer/bigpicture.css b/renderer/bigpicture.css index 9099553..1248d78 100644 --- a/renderer/bigpicture.css +++ b/renderer/bigpicture.css @@ -982,6 +982,22 @@ body.mouse-active { padding: var(--bp-spacing-lg); } +.osk-title { + display: flex; + align-items: center; + gap: var(--bp-spacing-md); + margin-bottom: var(--bp-spacing-md); + color: var(--bp-accent); + font-size: 1rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 1px; +} + +.osk-title .material-symbols-outlined { + font-size: 1.3rem; +} + .osk-header { display: flex; align-items: center; @@ -989,19 +1005,67 @@ body.mouse-active { margin-bottom: var(--bp-spacing-md); } +.osk-input-wrapper { + flex: 1; + position: relative; + display: flex; + align-items: center; + background: var(--bp-bg); + border: 2px solid var(--bp-accent); + border-radius: var(--bp-radius-md); + box-shadow: 0 0 20px var(--bp-accent-glow); + overflow: hidden; +} + .osk-text-input { flex: 1; padding: var(--bp-spacing-md) var(--bp-spacing-lg); - background: var(--bp-bg); - border: 2px solid var(--bp-border); - border-radius: var(--bp-radius-md); - font-size: 1.2rem; + background: transparent; + border: none; + font-size: 1.3rem; color: var(--bp-text); + font-weight: 500; + letter-spacing: 0.5px; + outline: none; } -.osk-text-input:focus { - outline: none; - border-color: var(--bp-accent); +.osk-text-input::placeholder { + color: var(--bp-text-dim); +} + +/* Blinking cursor that follows text */ +.osk-cursor { + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 3px; + height: 1.5em; + background: var(--bp-accent); + border-radius: 2px; + animation: blink-cursor 1s step-end infinite; + box-shadow: 0 0 8px var(--bp-accent); + pointer-events: none; + left: var(--bp-spacing-lg); +} + +/* Hidden element to measure text width */ +.osk-text-measure { + position: absolute; + visibility: hidden; + white-space: pre; + font-size: 1.3rem; + font-weight: 500; + letter-spacing: 0.5px; + font-family: inherit; +} + +@keyframes blink-cursor { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0; + } } .osk-close { diff --git a/renderer/bigpicture.html b/renderer/bigpicture.html index 75a8f87..d99aea8 100644 --- a/renderer/bigpicture.html +++ b/renderer/bigpicture.html @@ -254,8 +254,16 @@