Skip to content

Commit b8ed34e

Browse files
authored
Reset modifier button's state (#12187)
1 parent 031fbf4 commit b8ed34e

File tree

1 file changed

+60
-0
lines changed
  • systemvm/agent/noVNC/app

1 file changed

+60
-0
lines changed

systemvm/agent/noVNC/app/ui.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ const UI = {
2929
connected: false,
3030
desktopName: "",
3131

32+
// Modifier key configuration
33+
_modifierKeys: {
34+
shift: { keysym: KeyTable.XK_Shift_L, code: "ShiftLeft", buttonId: 'noVNC_toggle_shift_button' },
35+
ctrl: { keysym: KeyTable.XK_Control_L, code: "ControlLeft", buttonId: 'noVNC_toggle_ctrl_button' },
36+
alt: { keysym: KeyTable.XK_Alt_L, code: "AltLeft", buttonId: 'noVNC_toggle_alt_button' },
37+
windows: { keysym: KeyTable.XK_Super_L, code: "MetaLeft", buttonId: 'noVNC_toggle_windows_button' }
38+
},
39+
3240
statusTimeout: null,
3341
hideKeyboardTimeout: null,
3442
idleControlbarTimeout: null,
@@ -125,6 +133,11 @@ const UI = {
125133
document.getElementById("noVNC_status")
126134
.addEventListener('click', UI.hideStatus);
127135

136+
// Handle tab/window close to release modifier keys
137+
// This is critical for VMware VMs using websocket reverse proxy
138+
window.addEventListener('beforeunload', UI.handleBeforeUnload);
139+
window.addEventListener('pagehide', UI.handlePageHide);
140+
128141
// Bootstrap fallback input handler
129142
UI.keyboardinputReset();
130143

@@ -1740,6 +1753,39 @@ const UI = {
17401753
UI.idleControlbar();
17411754
},
17421755

1756+
_sendKeyUp(keysym, code) {
1757+
if (!UI.rfb) return;
1758+
UI.rfb.sendKey(keysym, code, false);
1759+
},
1760+
1761+
// Release a single modifier key if it's pressed
1762+
_releaseModifierKey(keyName) {
1763+
const keyConfig = UI._modifierKeys[keyName];
1764+
if (!keyConfig) return false;
1765+
1766+
const btn = document.getElementById(keyConfig.buttonId);
1767+
if (!btn || !btn.classList.contains("noVNC_selected")) {
1768+
return false;
1769+
}
1770+
1771+
UI._sendKeyUp(keyConfig.keysym, keyConfig.code);
1772+
btn.classList.remove("noVNC_selected");
1773+
return true;
1774+
},
1775+
1776+
// Release all currently pressed modifier keys
1777+
_releaseAllModifierKeys() {
1778+
let keysReleased = false;
1779+
1780+
// Release all modifier keys
1781+
for (const keyName in UI._modifierKeys) {
1782+
if (UI._releaseModifierKey(keyName)) {
1783+
keysReleased = true;
1784+
}
1785+
}
1786+
return keysReleased;
1787+
},
1788+
17431789
// Move focus to the screen in order to be able to use the
17441790
// keyboard right after these extra keys.
17451791
// The exception is when a virtual keyboard is used, because
@@ -1836,6 +1882,20 @@ const UI = {
18361882
selectbox.options.add(optn);
18371883
},
18381884

1885+
// Handle tab/window close events
1886+
// These fire when the user closes the tab, which doesn't call disconnect()
1887+
handleBeforeUnload(event) {
1888+
// Release modifier keys before tab closes
1889+
// This is critical for VMware VMs using websocket reverse proxy
1890+
UI._releaseAllModifierKeys();
1891+
},
1892+
1893+
handlePageHide(event) {
1894+
// Also handle pagehide as a fallback (fires in more browsers)
1895+
// Release modifier keys before page is hidden
1896+
UI._releaseAllModifierKeys();
1897+
},
1898+
18391899
/* ------^-------
18401900
* /MISC
18411901
* ==============

0 commit comments

Comments
 (0)