Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1146446
  • 博文数量: 222
  • 博客积分: 5262
  • 博客等级: 大校
  • 技术积分: 3028
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-22 19:10
文章分类

全部博文(222)

文章存档

2012年(2)

2011年(192)

2010年(28)

分类:

2011-01-26 11:09:50

浅析winvnc鼠标和屏幕信息的传送和鼠标数据算法处理

1.client端
void ClientConnection::Run()
==>ClientConnection::ReadServerInit
void ClientConnection::ReadServerInit()
{
    ReadExact((char *)&m_si, sz_rfbServerInitMsg);
    
    m_si.framebufferWidth = Swap16IfLE(m_si.framebufferWidth); // 比如1204

    m_si.framebufferHeight = Swap16IfLE(m_si.framebufferHeight); // 比如768

    m_si.format.redMax = Swap16IfLE(m_si.format.redMax);
    m_si.format.greenMax = Swap16IfLE(m_si.format.greenMax);
    m_si.format.blueMax = Swap16IfLE(m_si.format.blueMax);
    m_si.nameLength = Swap32IfLE(m_si.nameLength);
    ...
}

ClientConnection::WndProc
==>
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_MBUTTONDOWN:
    case WM_MBUTTONUP:
    case WM_RBUTTONDOWN:
    case WM_RBUTTONUP:
    case WM_MOUSEMOVE:
        {
            if (!_this->m_running) return 0;
            if (GetFocus() != hwnd) return 0;
            int x = LOWORD(lParam);
            int y = HIWORD(lParam);
            if (_this->InFullScreenMode()) {
                if (_this->BumpScroll(x,y))
                    return 0;
            }
            if ( _this->m_opts.m_ViewOnly) return 0;
            _this->ProcessPointerEvent(x,y, wParam, iMsg);
            return 0;
        }
==>ClientConnection::ProcessPointerEvent(int x, int y, DWORD keyflags, UINT msg)
==>SubProcessPointerEvent(x, y, keyflags);
inline void
ClientConnection::SubProcessPointerEvent(int x, int y, DWORD keyflags)
{
  int mask;
  
  if (m_opts.m_SwapMouse) {
        mask = ( ((keyflags & MK_LBUTTON) ? rfbButton1Mask : 0) |
            ((keyflags & MK_MBUTTON) ? rfbButton3Mask : 0) |
            ((keyflags & MK_RBUTTON) ? rfbButton2Mask : 0) );
    } else {
        mask = ( ((keyflags & MK_LBUTTON) ? rfbButton1Mask : 0) |
            ((keyflags & MK_MBUTTON) ? rfbButton2Mask : 0) |
            ((keyflags & MK_RBUTTON) ? rfbButton3Mask : 0) );
    }
    
    try {
        SendPointerEvent((x + m_hScrollPos) * m_opts.m_scale_den / m_opts.m_scale_num,
// client的实际窗口尺寸与server的framebufferWidth之间存在的scale缩放比例数值[luther.gliethttp].

                         (y + m_vScrollPos) * m_opts.m_scale_den / m_opts.m_scale_num, mask);
    } catch (Exception &e) {
        e.Report();
        PostMessage(m_hwnd, WM_CLOSE, 0, 0);
    }
}

inline void
ClientConnection::SendPointerEvent(int x, int y, int buttonMask)
{
    rfbPointerEventMsg pe;

    pe.type = rfbPointerEvent;
    pe.buttonMask = buttonMask;
    if (x < 0) x = 0;
    if (y < 0) y = 0;
    pe.x = Swap16IfLE(x);
    pe.y = Swap16IfLE(y);
    WriteExact((char *)&pe, sz_rfbPointerEventMsg);
}

2.server端
void vncClientThread::run(void *arg)
{
    ....
    // Send the server format message to the client

    rfbServerInitMsg server_ini;
    server_ini.format = m_client->m_buffer->GetLocalFormat();

    // Endian swaps

    server_ini.framebufferWidth = Swap16IfLE(m_client->m_fullscreen.right); // 比如1204

    server_ini.framebufferHeight = Swap16IfLE(m_client->m_fullscreen.bottom); // 比如768

    server_ini.format.redMax = Swap16IfLE(server_ini.format.redMax);
    server_ini.format.greenMax = Swap16IfLE(server_ini.format.greenMax);
    server_ini.format.blueMax = Swap16IfLE(server_ini.format.blueMax);

    server_ini.nameLength = Swap32IfLE(strlen(desktopname));
    m_socket->SendExact((char *)&server_ini, sizeof(server_ini)); // 发送server信息1

    m_socket->SendExact(desktopname, strlen(desktopname)); // 发送server信息2

    ...
}

vncDesktop::InitBitmap()
==>
 m_bmrect.left = m_bmrect.top = 0;
 m_bmrect.right = GetDeviceCaps(m_hrootdc, HORZRES); // 屏幕水平像素,比如:1024

 m_bmrect.bottom = GetDeviceCaps(m_hrootdc, VERTRES); // 屏幕垂直像素,比如:768


vncDesktop::SetPixFormat
==>m_scrinfo.framebufferWidth = (CARD16) (m_bmrect.right - m_bmrect.left);

vncClientThread::run
==>m_client->m_fullscreen = m_client->m_buffer->GetSize();

RECT
vncBuffer::GetSize()
{
    RECT rect;

    rect.left = 0;
    rect.top = 0;
    rect.right = m_scrinfo.framebufferWidth;
    rect.bottom = m_scrinfo.framebufferHeight;

    return rect;
}

server端,计算client发送过来的鼠标坐标

case rfbPointerEvent:
DWORD flags = MOUSEEVENTF_ABSOLUTE; // 鼠标值为绝对数值,非dx相对移动数值[luther.gliethttp]

// Generate coordinate values

unsigned long x = (msg.pe.x * 65535) / (m_client->m_fullscreen.right); // 计算绝对鼠标坐标值x

unsigned long y = (msg.pe.y * 65535) / (m_client->m_fullscreen.bottom); // 计算绝对鼠标坐标值y

如果使用了MOUSEEVENTF_ABSOLUTE标志,说明windows系统内部处理鼠标坐标时,屏幕左上角内部坐标值(0,0),屏幕右下角内部坐标值(65535,65535),
msg.pe.x和msg.pe.y是client经过绝对计算之后,server鼠标实际坐标值,因为我们要传递鼠标实际值,而不是相对值(dx,dy),所以
我们就需要将实际像素坐标转换为屏幕内部坐标值,比如:server的屏幕分辨率设为1024*768,那么
x=1024就应该对应内部坐标xo=65535,
y=768就应该对应内部坐标yo=768,所以(x,y)要先通过上面的转换,才能传给windows正常显示鼠标位置,因为windows系统内部,发现MOUSEEVENTF_ABSOLUTE标志
之后,会在windows系统内部执行相应的反运算,进而反应真实鼠标位置到1024*768分辨率的显示器上[luther.gliethttp].
比如我们现在由client传过来的坐标为(123,456),那么我们需要这样转换
123*(65535/1024)
456*(65535/768)
但是上面计算精度不高,所以就有了vnc server上面的转换代码,
(123*65535) / 1024
(456*65535) / 768
我想这样大家就应该明白了吧[luther.gliethttp]:)

阅读(2688) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~