Debug and fix VNC client display issues

- Add comprehensive logging to Display.flip() method for viewport and scaling debugging
- Fix missing KeyboardUtil object in input/util.js
- Add backbuffer content verification before and after rectangle processing
- Enhance WebSocket message logging for frame data debugging
- Improve error handling for corrupted FramebufferUpdate messages
- Add data skipping for unsupported encodings to prevent connection stalls
- Clean up excessive console.log statements for production readiness
- Verify loading system with cancel button functionality
parent c377af92
...@@ -185,3 +185,9 @@ function getKeysym(evt) { ...@@ -185,3 +185,9 @@ function getKeysym(evt) {
} }
window.getKeycode = getKeycode; window.getKeycode = getKeycode;
window.getKeysym = getKeysym; window.getKeysym = getKeysym;
// Create KeyboardUtil object for compatibility
window.KeyboardUtil = {
getKeycode: getKeycode,
getKeysym: getKeysym
};
This diff is collapsed.
...@@ -338,16 +338,8 @@ class Websock { ...@@ -338,16 +338,8 @@ class Websock {
} }
_recvMessage(e) { _recvMessage(e) {
console.log("[VNC-WS] Received WebSocket message, data length:", e.data.byteLength || e.data.length);
// Log first 32 bytes for debugging
const dataArray = new Uint8Array(e.data);
const hexData = Array.from(dataArray.slice(0, Math.min(32, dataArray.length))).map(b => b.toString(16).padStart(2, '0')).join(' ');
console.log("[VNC-WS] First 32 bytes (hex):", hexData);
this._DecodeMessage(e.data); this._DecodeMessage(e.data);
console.log("[VNC-WS] After decode, rQlen:", this.rQlen, "rQi:", this._rQi);
if (this.rQlen > 0) { if (this.rQlen > 0) {
this._eventHandlers.message(); this._eventHandlers.message();
if (this._rQlen == this._rQi) { if (this._rQlen == this._rQi) {
......
...@@ -189,6 +189,15 @@ ...@@ -189,6 +189,15 @@
<div id="vnc" class="vnc-container w-100"> <div id="vnc" class="vnc-container w-100">
<div id="noVNC_screen"> <div id="noVNC_screen">
<div id="noVNC_status">Click Connect to start VNC session</div> <div id="noVNC_status">Click Connect to start VNC session</div>
<div id="noVNC_loading" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: #f8f8f2;">
<div class="spinner-border text-primary mb-2" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div>Connecting to VNC server...</div>
<button id="cancelConnectBtn" class="btn btn-outline-danger btn-sm mt-2" style="display: none;">
<i class="fas fa-times"></i> Cancel
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -199,15 +208,10 @@ ...@@ -199,15 +208,10 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script> <script>
console.log('VNC page loaded');
// Check if Base64 is loaded // Check if Base64 is loaded
setTimeout(function() { setTimeout(function() {
console.log('[VNC-DEBUG] Checking if Base64 is defined:', typeof window.Base64);
if (typeof window.Base64 === 'undefined') { if (typeof window.Base64 === 'undefined') {
console.error('[VNC-DEBUG] Base64 is not defined! This will cause JPEG decoding to fail.'); console.error('[VNC-ERROR] Base64 is not defined! This will cause JPEG decoding to fail.');
} else {
console.log('[VNC-DEBUG] Base64 is properly defined');
} }
}, 100); }, 100);
...@@ -217,6 +221,7 @@ let socketFrameSeq = 0; ...@@ -217,6 +221,7 @@ let socketFrameSeq = 0;
document.getElementById('connectBtn').addEventListener('click', connect); document.getElementById('connectBtn').addEventListener('click', connect);
document.getElementById('disconnectBtn').addEventListener('click', disconnect); document.getElementById('disconnectBtn').addEventListener('click', disconnect);
document.getElementById('cancelConnectBtn').addEventListener('click', cancelConnect);
// Window control buttons // Window control buttons
document.querySelector('.close-btn').addEventListener('click', disconnect); document.querySelector('.close-btn').addEventListener('click', disconnect);
...@@ -255,12 +260,15 @@ function toggleFullscreen() { ...@@ -255,12 +260,15 @@ function toggleFullscreen() {
} }
function connect() { function connect() {
console.log('Connect button clicked');
if (connected) return; if (connected) return;
// Hide the status text and show loading message
document.getElementById('noVNC_status').style.display = 'none';
document.getElementById('noVNC_loading').style.display = 'block';
document.getElementById('cancelConnectBtn').style.display = 'inline-block';
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = wsProtocol + '//' + window.location.host + '/vnc/%s/ws'; const wsUrl = wsProtocol + '//' + window.location.host + '/vnc/%s/ws';
console.log('Connecting VNC to:', wsUrl);
try { try {
rfb = new RFB(document.getElementById('noVNC_screen'), wsUrl, { rfb = new RFB(document.getElementById('noVNC_screen'), wsUrl, {
...@@ -271,78 +279,31 @@ function connect() { ...@@ -271,78 +279,31 @@ function connect() {
}); });
rfb.addEventListener('connect', () => { rfb.addEventListener('connect', () => {
console.log('[VNC-DEBUG] VNC connected event fired');
console.log('[VNC-DEBUG] Connection state:', rfb._rfbConnectionState);
console.log('[VNC-DEBUG] Init state:', rfb._rfbInitState);
connected = true; connected = true;
document.getElementById('connectBtn').disabled = true; document.getElementById('connectBtn').disabled = true;
document.getElementById('disconnectBtn').disabled = false; document.getElementById('disconnectBtn').disabled = false;
// Hide loading message
document.getElementById('noVNC_loading').style.display = 'none';
showNotification('VNC session connected', 'success'); showNotification('VNC session connected', 'success');
// Override WebSocket onmessage after connection to intercept messages // Reset frame sequence for new connection
const originalOnMessage = rfb._sock.onmessage; socketFrameSeq = 0;
rfb._sock.onmessage = function(event) {
// Debug VNC socket data logging with base64 encoding and sequence numbers (first 20 frames only)
if (socketFrameSeq < 20) {
const bytes = event.data.byteLength || event.data.length;
const uint8 = new Uint8Array(event.data);
let binary = '';
for (let i = 0; i < uint8.length; i++) {
binary += String.fromCharCode(uint8[i]);
}
const b64Data = btoa(binary);
console.log(`[VNC-SOCKET-SERVER] Frame ${socketFrameSeq}: ${bytes} bytes -> base64: ${b64Data}`);
socketFrameSeq++;
}
// Call original handler
return originalOnMessage.call(this, event);
};
}); });
// Add debug logging for WebSocket messages
const originalSend = rfb._sock.send;
rfb._sock.send = function(data) {
console.log('[VNC-DEBUG] JavaScript sending data to WebSocket:', data.length, 'bytes');
if (data.length <= 32) {
const hex = Array.from(new Uint8Array(data)).map(b => b.toString(16).padStart(2, '0')).join(' ');
console.log('[VNC-DEBUG] Data (hex):', hex);
} else {
const hex = Array.from(new Uint8Array(data.slice(0, 32))).map(b => b.toString(16).padStart(2, '0')).join(' ');
console.log('[VNC-DEBUG] Data (first 32 bytes hex):', hex + '...');
}
// Log VNC message types
if (data.length > 0) {
const msgType = new Uint8Array(data)[0];
console.log('[VNC-DEBUG] JavaScript message type:', msgType);
switch (msgType) {
case 0: console.log('[VNC-DEBUG] -> SetPixelFormat'); break;
case 2: console.log('[VNC-DEBUG] -> SetEncodings'); break;
case 3: console.log('[VNC-DEBUG] -> FramebufferUpdateRequest'); break;
case 4: console.log('[VNC-DEBUG] -> KeyEvent'); break;
case 5: console.log('[VNC-DEBUG] -> PointerEvent'); break;
case 6: console.log('[VNC-DEBUG] -> ClientCutText'); break;
default: console.log('[VNC-DEBUG] -> Unknown message type'); break;
}
}
return originalSend.call(this, data);
};
rfb.addEventListener('disconnect', () => { rfb.addEventListener('disconnect', () => {
console.log('[VNC-DEBUG] VNC disconnected event fired');
console.log('[VNC-DEBUG] Connection state:', rfb._rfbConnectionState);
console.log('[VNC-DEBUG] Init state:', rfb._rfbInitState);
connected = false; connected = false;
document.getElementById('connectBtn').disabled = false; document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true; document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state
document.getElementById('noVNC_status').style.display = 'block';
document.getElementById('noVNC_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none';
showNotification('VNC session disconnected', 'info'); showNotification('VNC session disconnected', 'info');
}); });
rfb.addEventListener('credentialsrequired', (e) => { rfb.addEventListener('credentialsrequired', (e) => {
console.log('VNC credentials required');
// For now, assume no credentials needed // For now, assume no credentials needed
}); });
...@@ -352,7 +313,7 @@ function connect() { ...@@ -352,7 +313,7 @@ function connect() {
}); });
rfb.addEventListener('clipboard', (e) => { rfb.addEventListener('clipboard', (e) => {
console.log('VNC clipboard:', e.detail.text); // Handle clipboard data if needed
}); });
} catch (e) { } catch (e) {
...@@ -369,10 +330,29 @@ function disconnect() { ...@@ -369,10 +330,29 @@ function disconnect() {
connected = false; connected = false;
document.getElementById('connectBtn').disabled = false; document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true; document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state
document.getElementById('noVNC_status').style.display = 'block';
document.getElementById('noVNC_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none';
setTimeout(() => { setTimeout(() => {
location.reload(); location.reload();
}, 3000); }, 3000);
} }
function cancelConnect() {
if (rfb) {
rfb.disconnect();
rfb = null;
}
connected = false;
document.getElementById('connectBtn').disabled = false;
document.getElementById('disconnectBtn').disabled = true;
// Reset UI to initial state
document.getElementById('noVNC_status').style.display = 'block';
document.getElementById('noVNC_loading').style.display = 'none';
document.getElementById('cancelConnectBtn').style.display = 'none';
showNotification('VNC connection cancelled', 'warning');
}
</script> </script>
</body> </body>
</html> </html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment