简体   繁体   English

将客户端坐标转换为像素坐标,以模拟MFC中的鼠标单击

[英]Converting client coordinates to Pixel coordinates for simulating a mouse click in MFC

I am trying to simulate a mouse click on the CView window in a legacy code which I must say I don't fully understand. 我试图用传统代码模拟在CView窗口上的鼠标单击,我必须说我不太了解。 The idea is to search for a particular item in the CView , get its co-ordinates and then simulate a right mouse click on it using SendInput . 这个想法是在CView搜索特定项目,获取其坐标,然后使用SendInput模拟鼠标右键单击它。 I want to understand if the basic steps I am following are correct before I proceed digging further into the legacy code which has a bunch of transformations happening across co-ordinate systems :( Here are the steps I follow: 我想了解我遵循的基本步骤是否正确,然后再继续研究遗留代码,该遗留代码在坐标系统之间发生了一堆转换:(以下是我遵循的步骤:

  1. Get the position co-ordinates of the item displayed in CView . 获取CView显示的项目的位置坐标。 at this point the co-ordinates is in the internal co-ordinate system (lets call it CDPoint ). 此时,坐标位于内部坐标系统中(称为CDPoint )。

    CDPoint gPosn = viewObj->m_point_a ;

  2. Covert the co-ordinates to the client co-ordinate system ie CDPoint to CPoint using the existing transformations in the code. 使用代码中的现有转换将坐标覆盖到客户坐标系统,即CDPoint到CPoint。

    CPoint newPosn = GetTransform().Scale(gPosn);

//Note: The basis of arriving that this is the correct transformation to use is the below code with the exact reverse transform happening in the mouse click handler code to convert CPoint to CDPoint : //注意:这是正确使用的转换的基础是以下代码,在鼠标单击处理程序代码CPoint CDPoint转换为CPoint ,发生了确切的反向转换:

 `CDesignView::OnLButtonDown(UINT nFlags, CPoint p) {
      CDPoint np = GetTransform().DeScale(p);
 }`

Is this thinking right that CPoint received in the OnLButtonDown() handler will always be in the client co-ordinates and hence the reverse transform should convert CDPoint (internal co-ordinates) to client coordinates (CPoint) ? 这样的想法对吗,OnLButtonDown()处理程序中接收到的CPoint将始终位于客户端坐标中,因此反向转换应将CDPoint(内部坐标)转换为客户端坐标(CPoint)?

  1. Convert client co-ordinates to screen co-ordinates: 将客户坐标转换为屏幕坐标:

    ClientToScreen(&newPosn);

  2. Pass these values to SendInput function after converting to pixel co-ordinates: 转换为像素坐标后,将这些值传递给SendInput函数:

    INPUT buffer[1]; MouseSetup(buffer); MouseMoveAbsolute(buffer, newPos.x, newPos.y); MouseClick(buffer);

  3. The Mousexxx() functions are defined as below similar to the sample code in this post: How to simulate a mouse movement 下面定义了Mousexxx()函数,类似于本文中的示例代码: 如何模拟鼠标移动

.

#define SCREEN_WIDTH (::GetSystemMetrics( SM_CXSCREEN )-1) 
#define SCREEN_HEIGHT (::GetSystemMetrics( SM_CYSCREEN )-1) 

static void inline makeAbsXY(double &x, double &y) { 
    x = (x * 0xFFFF) / SCREEN_WIDTH ; 
    y = (y * 0xFFFF) / SCREEN_HEIGHT ; 
}

static void inline MouseSetup(INPUT *buffer)
{
    buffer->type = INPUT_MOUSE;
    buffer->mi.dx = (0 * (0xFFFF / SCREEN_WIDTH));
    buffer->mi.dy = (0 * (0xFFFF / SCREEN_HEIGHT));
    buffer->mi.mouseData = 0;
    buffer->mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
    buffer->mi.time = 0;
    buffer->mi.dwExtraInfo = 0;
}

static void inline MouseMoveAbsolute(INPUT *buffer, double x, double y)
{
    makeAbsXY(x,y) ; 
    buffer->mi.dx = x ;
    buffer->mi.dy = y ;
    buffer->mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE);
    SendInput(1, buffer, sizeof(INPUT));
}

static void inline MouseClick(INPUT *buffer)
{
    buffer->mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_RIGHTDOWN);
    SendInput(1, buffer, sizeof(INPUT));
    Sleep(10);
    buffer->mi.dwFlags = (MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_RIGHTUP);
    SendInput(1, buffer, sizeof(INPUT));
}

Could anyone pls provide pointers on what might be going wrong in these steps since the simulated mosue click always seem to be shifted left by some factor which keeps increasing as x becoems larger. 任何人都可以提供有关这些步骤中可能出问题的指针的信息,因为模拟的mosue咔嗒声似乎总是向左移动了某个因素,而随着x bemeem的增加,这种因素会不断增加。 I have verified that is gPosn is pointing to (0,0) it always simulates a mouse click on the top right corner of the client screen. 我已验证gPosn指向(0,0),它始终模拟客户端屏幕右上角的鼠标单击。

Thanks for your time. 谢谢你的时间。

If you have x and y in client coordinates, you have to convert them to screen coordinates: 如果客户坐标中包含xy ,则必须将它们转换为屏幕坐标:

POINT point;
point.x = x;
point.y = y;
::ClientToScreen(m_hWnd, point);

Where m_hWnd is the window which owns the objects. 其中m_hWnd是拥有对象的窗口。 x and y are relative to top-left of the client area of this window. xy相对于此窗口客户区的左上角。

Assuming point.x and point.y are in screen coordinates, the rest of the conversion for SendInput is correct. 假设point.xpoint.y在屏幕坐标中, SendInput的其余转换是正确的。 You can also create INPUT array for SendInput , this will send the mouse messages without interruption. 您也可以为SendInput创建INPUT数组,这将不中断地发送鼠标消息。

INPUT input[3];
for (int i = 0; i < 3; i++)
{
    memset(&input[i], 0, sizeof(INPUT));
    input[i].type = INPUT_MOUSE;
}

input[0].mi.dx = (point.x * 0xFFFF) / (GetSystemMetrics(SM_CXSCREEN) - 1);
input[0].mi.dy = (point.y * 0xFFFF) / (GetSystemMetrics(SM_CYSCREEN) - 1);
input[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
input[1].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
input[2].mi.dwFlags = MOUSEEVENTF_RIGHTUP;

SendInput(3, input, sizeof(INPUT));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM