Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Kết quả 1 đến 8 của 8
  1. #1
    Ngày tham gia
    Sep 2015
    Bài viết
    0

    Giả lập thao tác Drag của chuột trên một cửa sổ khác

    Nội dung như tiêu đề cụ thể là mình muốn tự động gửi một chuỗi message giả lập thao tác rê chuột lên một cửa sổ (đã lấy handle). Dưới đây là code của mình, sử dụng lần lượt các hàm PostMessage để gửi đi 3 sự kiện WM_LBUTTONDOWN, WM_MOUSEMOVE và WM_LBUTTONUP đúng như thao tác thật mình quan sát trong spy++
    Mã:
    BOOL success;
        LPARAM param;
    
    
        for (int i = 10; i < 30; i++)
        {
            param = MAKELPARAM(i, 30);
            if (i == 10) success = PostMessage(hwnd, WM_LBUTTONDOWN, MK_LBUTTON, param);
            success &= PostMessage(hwnd, WM_MOUSEMOVE, MK_LBUTTON, param);
            //Sleep(100);
        }
        success &= PostMessage(hwnd, WM_LBUTTONUP, 0x0000, param);
    kết quả mình nhận được chỉ là một thao tác click tại vị trí bắt đầu mặc dù message vẫn hiện đủ trong spy++ mong các cao nhân chỉ giúp ạ!

  2. #2
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Trong mã của bạn, mình nêu một vài ý kiến ( không chắc chắn lắm) như sau :
    _ Bạn dùng API PostMessage, các lời gọi hàm của bạn sẽ tạo các thông điệp xếp hàng trong hàng đợi thông điệp mà Windows đã tạo cho cửa sổ mà bạn đã lấy handle.
    _ Đối với Windows, các thông điệp WM_MOUSEMOVE có độ ưu tiên thấp ( cũng giống như WM_TIMER - Tùy theo HĐH). Điều này có nghĩa là 30 thông điệp mà bạn đã gởi, Windows có thể chỉ gộp lại và truyền tới hàm xử lý thông điệp ( WindowProc) của cửa sổ chỉ 1 mà thôi nếu ( trong trường hợp của bạn có lẽ đúng là như vậy).
    _ Trong thông điệp cuối cùng ( WM_LBUTTONUP), bạn vẫn phải giữ tham số wParam là MK_LBUTTON (0x0001) cho các hoạt động bên trong của Windows.
    _ Bạn cũng phải lưu ý trong mã nếu có mô phỏng chuột di chuyển ngang qua các điều khiển con của cửa sổ hay không.
    _ Cuối cùng, nếu phải giả lập thao tác Drag của chuột, mình sẽ chọn API SendInput sẽ có phần nhẹ nhàng hơn.
    Nếu bạn thấy chưa thỏa đáng, có thể đưa mã của bạn lên không . Hoặc nếu có thời gian, mình sẽ tạo một chương trình nhỏ minh họa cho đề tài này. Thân

  3. #3
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    cửa sổ demo của mình chỉ là 1 WinForm (mình tạo bằng C# - đã viết sẵn sự kiện vẽ khi drag chuột để detect) và không có control gì khác trên ấy cả. Toàn bộ mã xử lý của mình chỉ có chừng đó. Nếu được bạn có thể demo code minh họa của bạn được không?
    cám ơn bạn rất nhiều [IMG]images/smilies/biggrin.png[/IMG]

  4. #4
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Mình viết tạm ra đây 1 hàm có thể có ích cho bạn. Do viết vội nên độ sai lệch của nó có thể là 1 Pixel, bạn có thể dùng double để chính xác hơn.
    Nếu bạn đã có handle của 1 cửa sổ, và muốn thực hiện thao tác kéo từ điểm A đến điểm B tính theo tọa độ cửa sổ, bạn phải chuyển tọa độ của A và B
    ra tọa độ màn hình ( có thể dùng API ClientToScreen ) rồi đưa vào làm đối số cho hàm bên dưới.

    Mã:
    // Đầu vào ://      ptStart: Con trỏ Chứa tọa độ điểm bắt đầu Drag tính theo màn hình//      ptEnd: Con trỏ Chứa tọa độ điểm cuối cùng cần kéo tới tính theo màn hình//      iSleep: Chứa mily giây làm trễ chuột, để ở giá trị 10 là đẹp nhấtvoid DragMouse(POINT * ptStart,POINT * ptEnd,int iSleep){    INPUT   Input = {0};    int     cxScreen = GetSystemMetrics(SM_CXSCREEN);       // Chiều rộng màn hình    int     cyScreen = GetSystemMetrics(SM_CYSCREEN);       // Chiều cao màn hình    int     xCurrent = ptStart->x;                          // Tọa độ x tính theo màn hình    int     yCurrent = ptStart->y;                          // Tọa độ y tính theo màn hình     // Mô phỏng di chuyển tới vị trí đầu tiên và nhấn chuột    Input.type          = INPUT_MOUSE;    Input.mi.dwFlags    = MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE|MOUSEEVENTF_LEFTDOWN;    Input.mi.dx         = ((65536 / cxScreen) * xCurrent - 1);  // Công thức tính Absolute dx cho cấu trúc    Input.mi.dy         = ((65536 / cyScreen) * yCurrent - 1);  // Công thức tính Absolute dy cho cấu trúc    SendInput(1,&Input,sizeof(INPUT));                          Sleep(iSleep);    // Vòng lặp mô phỏng Drag chuột    Input.mi.dwFlags    = MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE;    while(xCurrent != ptEnd->x || yCurrent != ptEnd->y)    {        if(ptStart->x < ptEnd->x)        {            if(++xCurrent > ptEnd->x)                xCurrent--;        }        else if(ptStart->x > ptEnd->x)        {            if(--xCurrent < ptEnd->x)                xCurrent++;        }         if(ptStart->y < ptEnd->y)        {            if(++yCurrent > ptEnd->y)                yCurrent--;        }        else if(ptStart->y > ptEnd->y)        {            if(--yCurrent < ptEnd->y)                yCurrent++;        }         Input.mi.dx     = ((65536 / cxScreen) * xCurrent - 1);        Input.mi.dy     = ((65536 / cyScreen) * yCurrent - 1);        SendInput(1,&Input,sizeof(INPUT));        Sleep(iSleep);    }    // Mô phỏng nhả chuột    Input.mi.dwFlags    = MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP;    SendInput(1,&Input,sizeof(INPUT));}
    Mã sau dùng double sẽ chạy chính xác hơn

    Mã:
    void DragMouse(POINT * ptStart,POINT * ptEnd,int iSleep){    INPUT       Input = {0};    double      dx = 65535.0f/(GetSystemMetrics(SM_CXSCREEN)-1);    // Hệ số dx    double      dy = 65535.0f/(GetSystemMetrics(SM_CYSCREEN)-1);    // Hệ số dy    double      xCurrent = ptStart->x;                              // Tọa độ x tính theo màn hình    double      yCurrent = ptStart->y;                              // Tọa độ y tính theo màn hình    // Mô phỏng di chuyển tới vị trí đầu tiên và nhấn chuột    Input.type          = INPUT_MOUSE;    Input.mi.dwFlags    = MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE|MOUSEEVENTF_LEFTDOWN;    Input.mi.dx         = (long)(dx*xCurrent);    Input.mi.dy         = (long)(dy*yCurrent);    SendInput(1,&Input,sizeof(INPUT));                          Sleep(iSleep);    // Vòng lặp mô phỏng Drag chuột    Input.mi.dwFlags    = MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE;    while(xCurrent != ptEnd->x || yCurrent != ptEnd->y)    {        if(ptStart->x < ptEnd->x)        {            if(++xCurrent > ptEnd->x)                xCurrent--;        }        else if(ptStart->x > ptEnd->x)        {            if(--xCurrent < ptEnd->x)                xCurrent++;        }         if(ptStart->y < ptEnd->y)        {            if(++yCurrent > ptEnd->y)                yCurrent--;        }        else if(ptStart->y > ptEnd->y)        {            if(--yCurrent < ptEnd->y)                yCurrent++;        }         Input.mi.dx     = (long)(dx*xCurrent);        Input.mi.dy     = (long)(dy*yCurrent);        SendInput(1,&Input,sizeof(INPUT));        Sleep(iSleep);    }    // Mô phỏng nhả chuột    Input.mi.dwFlags    = MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_LEFTUP;    SendInput(1,&Input,sizeof(INPUT));}

  5. #5
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    không có cách nào để giả lập mà không phải make foreground cho cửa sổ đích hở bạn

  6. #6
    Mình không hiểu ý nghĩa của từ "make foreground" do tiếng Anh của mình chỉ bập bẹ được vài chữ thôi, bạn có thể nói rõ hơn không.

  7. #7
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    nghĩa là nếu send input như vậy thì mình buộc phải dùng SetForegroundWindow(hwnd) để active cửa sổ mà mình muốn giả lập drag chuột lên rồi mới send input được

  8. #8
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Mình lại nghĩ bạn không cần phải dùng SetForegroundWindow để kích hoạt cửa sổ mà cần giả lập Drag chuột.
    Nếu chương trình mà bạn viết bằng C# ấy được viết đúng đắn thì nó sẽ nhận được ngững gì mà nó muốn thôi.
    Bên dưới là một chương trình rất nhỏ mình viết dưói VS 2012, sử dụng MFC trên hộp thoại sẽ minh họa thêm cho mục đích này.

    Để sử dụng chương trình này, bạn chọn 1 chương trình trong Listbox, nhập vào tọa độ điểm đầu và điểm cuối cần Drag
    tính theo tọa độ Client của cửa sổ đã chọn.
    Nhấn nút Drag để thực hiện giả lập kéo chuột.
    Nút Reload để nạp lại các cửa sổ cho Listbox.

 

 

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •