Wake the player HUD on mouse movement (desktop)
The fullscreen player only revealed its HUD on a tap, a key press or a transport action, so on a PC the controls stayed hidden while the mouse moved over the video -- the reels feed already woke its own HUD on mousemove, so this was the odd one out. Any mouse movement over the player now wakes it, and it stays up while the pointer rests on the top or bottom bar rather than fading out from under the cursor. Touch and pen are excluded on purpose: taps already wake the HUD, and a finger dragging for volume or a dismiss swipe isn't someone looking for the controls. The listeners go on the bars rather than .cp-hud, which is pointer-events:none so it never eats gestures over the video. Verified with synthesized mouse input in headless Chrome: idle 3.2s -> hidden; move over the video -> shown; still 3.2s -> hidden again; onto the controls -> shown and still shown after 3.4s resting there; back over the video and still -> hidden. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QBDkEXP4htyXTCZUwMLphd
This commit is contained in:
@@ -23,6 +23,7 @@ App.player = App.player || {};
|
||||
historyPushed: false,
|
||||
idleTimer: null,
|
||||
originEl: null,
|
||||
hudHovered: false, // mouse resting on the controls (desktop)
|
||||
attemptToken: 0 // bumps on every open()/format switch to void stale async callbacks
|
||||
};
|
||||
|
||||
@@ -145,6 +146,11 @@ App.player = App.player || {};
|
||||
clearIdleTimer();
|
||||
cp.idleTimer = setTimeout(() => {
|
||||
cp.idleTimer = null;
|
||||
// Never fade out from under a mouse resting on the controls.
|
||||
if (cp.hudHovered) {
|
||||
scheduleHudHide();
|
||||
return;
|
||||
}
|
||||
if (cp.container) cp.container.classList.add('cp-hud-idle');
|
||||
}, HUD_IDLE_MS);
|
||||
}
|
||||
@@ -449,6 +455,64 @@ App.player = App.player || {};
|
||||
addCleanup(destroy);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Mouse presence (desktop): moving the mouse anywhere over the player
|
||||
// brings the HUD back, and it stays up while the pointer rests on the
|
||||
// controls. Touch input is deliberately excluded -- taps already wake the
|
||||
// HUD, and a finger dragging for volume or a dismiss swipe shouldn't count
|
||||
// as "the viewer went looking for the controls".
|
||||
// ---------------------------------------------------------------------
|
||||
function bindHoverHud() {
|
||||
const container = cp.container;
|
||||
if (!container) return;
|
||||
const isMouse = (event) => !event.pointerType || event.pointerType === 'mouse';
|
||||
|
||||
let lastWake = 0;
|
||||
const onMove = (event) => {
|
||||
if (!isMouse(event)) return;
|
||||
// wakeHud() re-arms the idle timer; once every 150ms is plenty and
|
||||
// keeps a fast mouse from churning timers on every pixel.
|
||||
const now = (window.performance && performance.now()) ? performance.now() : Date.now();
|
||||
if (now - lastWake < 150) return;
|
||||
lastWake = now;
|
||||
wakeHud();
|
||||
};
|
||||
const onEnterHud = (event) => {
|
||||
if (!isMouse(event)) return;
|
||||
cp.hudHovered = true;
|
||||
wakeHud();
|
||||
};
|
||||
const onLeaveHud = (event) => {
|
||||
if (!isMouse(event)) return;
|
||||
cp.hudHovered = false;
|
||||
scheduleHudHide();
|
||||
};
|
||||
const onLeaveContainer = (event) => {
|
||||
if (!isMouse(event)) return;
|
||||
cp.hudHovered = false;
|
||||
};
|
||||
|
||||
container.addEventListener('pointermove', onMove);
|
||||
container.addEventListener('pointerleave', onLeaveContainer);
|
||||
// The bars, not .cp-hud itself: the HUD wrapper is pointer-events:none
|
||||
// (so it never eats gestures over the video) and only its children are
|
||||
// hit-testable.
|
||||
const bars = [q('.cp-top-bar'), q('.cp-bottom-bar')].filter(Boolean);
|
||||
bars.forEach((bar) => {
|
||||
bar.addEventListener('pointerenter', onEnterHud);
|
||||
bar.addEventListener('pointerleave', onLeaveHud);
|
||||
});
|
||||
addCleanup(() => {
|
||||
cp.hudHovered = false;
|
||||
container.removeEventListener('pointermove', onMove);
|
||||
container.removeEventListener('pointerleave', onLeaveContainer);
|
||||
bars.forEach((bar) => {
|
||||
bar.removeEventListener('pointerenter', onEnterHud);
|
||||
bar.removeEventListener('pointerleave', onLeaveHud);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Keyboard shortcuts (desktop)
|
||||
// ---------------------------------------------------------------------
|
||||
@@ -840,6 +904,7 @@ App.player = App.player || {};
|
||||
});
|
||||
}
|
||||
bindGestures(cp.video);
|
||||
bindHoverHud();
|
||||
bindKeyboard(cp.video);
|
||||
bindClose();
|
||||
bindBufferingIndicator(cp.video);
|
||||
|
||||
Reference in New Issue
Block a user