diff --git a/static/client.html b/static/client.html index cf47719..d5f7166 100644 --- a/static/client.html +++ b/static/client.html @@ -1466,14 +1466,37 @@ if (x) { try { x.call(document); } catch (e) {} } } function rgArmFullscreenGesture() { - var fire = function() { + var fire = function(e) { document.removeEventListener('mousedown', fire, true); document.removeEventListener('keydown', fire, true); + // This press is the browser's fullscreen gesture, not + // input for the remote. The transition it starts re-lays + // out the display and swallows the matching release, and + // a press guacd never sees released turns every later + // pointer move into a drag selection (#256). Keep it from + // the display's handlers; rgReleaseAllInput() covers a + // release lost for any other reason once fullscreen lands. + e.stopPropagation(); + e.preventDefault(); rgEnterFullscreen(); }; document.addEventListener('mousedown', fire, true); document.addEventListener('keydown', fire, true); } + // Tell the remote that nothing is held: every key the keyboard + // tracks as down, and all mouse buttons at the last pointer + // position. Used after a fullscreen transition, during which the + // browser may not deliver the releases to the display element. + function rgReleaseAllInput() { + try { if (keyboard) keyboard.reset(); } catch (e) {} + try { + if (!mouse || !mouse.currentState) return; + var st = new Guacamole.Mouse.State(mouse.currentState); + st.left = st.middle = st.right = st.up = st.down = false; + if (fillX !== 1 || fillY !== 1) { st.x /= fillX; st.y /= fillY; } + client.sendMouseState(st, true); + } catch (e) {} + } function rgShowEscNoticeOnce() { if (sessionStorage.getItem('rustguac_esc_notice_seen')) return; sessionStorage.setItem('rustguac_esc_notice_seen', '1'); @@ -1526,6 +1549,7 @@ function rgOnFullscreenChange() { var inFs = !!rgFullscreenEl(); var bar = document.getElementById('fs-bar'); + if (inFs) rgReleaseAllInput(); if (bar) { if (inFs) { bar.classList.add('visible');