LibVNC / libvncserver

LibVNCServer/LibVNCClient are cross-platform C libraries that allow you to easily implement VNC server or client functionality in your program.
GNU General Public License v2.0
1.07k stars 481 forks source link

I want to get the mouse position in the VNC server. I set a callback, but it never triggers. Even if I force a full frame request, it still has no effect. I still receive a rectangular image of the area. #623

Closed YFforever2022 closed 2 days ago

YFforever2022 commented 6 days ago

I want to get the mouse position in the VNC server. I set a callback, but it never triggers. Even if I force a full frame request, it still has no effect. I still receive a rectangular image of the area.

Environment:

Windows 10 VMware 16.1.2 Latest code branch

Code:

#include <rfb/rfbclient.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>
#include <mutex>

// Global variables
std::mutex globalLock;
std::vector<unsigned char> globalBuffer; // Buffer to store the entire screen
int screenWidth = 0;
int screenHeight = 0;

// Function to save the accumulated buffer as BMP
void SaveBufferAsBMP(const char* filename) {
    // Check if we have valid screen dimensions
    if (screenWidth <= 0 || screenHeight <= 0) {
        std::cerr << "Invalid screen dimensions." << std::endl;
        return;
    }

    BITMAPFILEHEADER bf = { 0 };
    bf.bfType = 0x4d42;
    bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 

    // BMP info header
    BITMAPINFOHEADER bi = { 0 };
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = screenWidth;
    bi.biHeight = screenHeight;
    bi.biPlanes = 1;
    bi.biBitCount = 32;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = globalBuffer.size();

    // Open the output file
    std::ofstream output(filename, std::ios::binary);
    if (!output) {
        std::cerr << "Error opening output file" << std::endl;
        return;
    }
    // Write the BMP file header and info header
    output.write(reinterpret_cast<char*>(&bf), sizeof(bf));
    output.write(reinterpret_cast<char*>(&bi), sizeof(bi));
    output.write(reinterpret_cast<char*>(globalBuffer.data()), globalBuffer.size());
    output.close();
}

// Framebuffer update callback
static void myGotFrameBufferUpdate(rfbClient* client, int x, int y, int w, int h) {

    std::lock_guard<std::mutex> lock(globalLock);
    int bpp = client->format.bitsPerPixel / 8; // Bytes per pixel

    if (screenWidth != client->width || screenHeight != client->height) {
        screenWidth = client->width;
        screenHeight = client->height;
        globalBuffer.resize(screenWidth * screenHeight * bpp);
    }

    for (int i = 0; i < h; ++i) {
        // Calculate the source and destination pointers
        unsigned char* src = client->frameBuffer + ((y + i) * client->width + x) * bpp;
        //unsigned char* dst = globalBuffer.data() + ((screenHeight - 1 - (y + i)) * screenWidth + x) * bpp;
        unsigned char* dst = globalBuffer.data() + ( (y + i) * screenWidth + x) * bpp;

        // Copy a single row of pixels
        memcpy(dst, src, w * bpp);
    }

}

rfbBool myHandleCursorPos(_rfbClient* client, int x, int y)
{
    std::cout << x << "," << y << std::endl;
    return 1;
}

void myGotCursorShape(_rfbClient* client, int xhot, int yhot, int width, int height, int bytesPerPixel)
{
    std::cout << "myGotCursorShape:" << xhot << "," << yhot << "," << width << "," << height << "," << bytesPerPixel << std::endl;
}

int main(int argc, char** argv) {
    rfbClient* client = rfbGetClient(8, 3, 4); // Initialize the VNC client

    std::string temp_ip = "127.0.0.1";
    char* ip = (char*)malloc(temp_ip.length() + 1);
    memcpy(ip, temp_ip.c_str(), temp_ip.length());
    ip[temp_ip.length()] = '\0';
    client->serverHost = ip;
    client->serverPort = 5900;
    client->connectTimeout = 3000;
    client->GotFrameBufferUpdate = myGotFrameBufferUpdate;
    client->HandleCursorPos = myHandleCursorPos;
    client->GotCursorShape = myGotCursorShape;
    client->appData.useRemoteCursor = TRUE;
    client->appData.compressLevel = 0;
    client->appData.qualityLevel = 100;

    if (!rfbInitClient(client, nullptr, nullptr)) {
        std::cerr << "Error connecting to VNC server" << std::endl;
        return 1;
    }

    client->appData.encodingsString = "raw";
    SetFormatAndEncodings(client);

    while (1) 
    {

        int n = WaitForMessage(client, 50);
        if (n < 0)
            break;
        if (n)
            if (!HandleRFBServerMessage(client))
                break;

        SendFramebufferUpdateRequest(client, 0, 0, client->width, client->height, FALSE);

    }

    rfbClientCleanup(client);
    return 1;
}
YFforever2022 commented 3 days ago

Is this because the VNC server does not support it?

bk138 commented 3 days ago

Is this because the VNC server does not support it?

That's probably the case. I suggest you look at the client and server logs, read https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst and maybe inspect the protocol flow via WireShark.

YFforever2022 commented 3 days ago

Is this because the VNC server does not support it?

That's probably the case. I suggest you look at the client and server logs, read https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst and maybe inspect the protocol flow via WireShark.

This document is very useful to me, thank you for your help