首页 > 编程语言 >C++ 截图、操作鼠标移动左键单击、操作键盘、ocr识图、获取system函数的结果

C++ 截图、操作鼠标移动左键单击、操作键盘、ocr识图、获取system函数的结果

时间:2023-02-27 17:34:31浏览次数:27  
标签:inputs ListNode 鼠标 单击 int mi 识图 next ocr

ocr识别是使用tesseract来搞得,因为tesseract的编译太麻烦了,就通过system直接命令行识别了在通过读取命令行界面的字符获取结果的。

//键盘和对应按键值的映射
std::map<wchar_t, unsigned int>key_vlaue{ {L'0',0x60},{L'1',0x61},{L'2',0x62},{L'3',0x63},{L'4',0x604},{L'5',0x65},{L'6',0x66},{L'7',0x67},{L'8',0x68},{L'9',0x69} };

struct ListNode {
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};
 /*
 * 移动到指定位置并左键单击
 */
void move_left_clik_mouse(int x, int y) {
    SetCursorPos(x, y);    //鼠标移动到指定位置,print screen键很有用
    INPUT inputs[2]{};

    inputs[0].type = INPUT_MOUSE;    //鼠标事件
    inputs[0].mi.dx = x;
    inputs[0].mi.dy = y;
    inputs[0].mi.mouseData = 0;
    inputs[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
    inputs[0].mi.time = 0;
    inputs[0].mi.dwExtraInfo = GetMessageExtraInfo();

    inputs[1].type = INPUT_MOUSE;    //鼠标事件
    inputs[1].mi.dx = x;
    inputs[1].mi.dy = y;
    inputs[1].mi.mouseData = 0;
    inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
    inputs[1].mi.time = 0;
    inputs[1].mi.dwExtraInfo = GetMessageExtraInfo();

    UINT uSent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
    if (uSent != ARRAYSIZE(inputs))
    {
        std::cout << "点击失败:" << HRESULT_FROM_WIN32(GetLastError());
    }
}
/*
* 本代码和信息按“原样”提供,不提供任何明示或暗示的保证,包括但不限于对适销性和/或特定用途适用性的暗示保证。
* FUNCTION: CaptureAnImage(HWND hWnd)
* 目的:将屏幕截图捕获到窗口中,然后将其保存在 .bmp 文件中。
* 注意:此函数默认尝试创建一个名为 captureqwsx.bmp 的文件
* 
* 应该要避免截取到多余的地方
* 
* HWND hWnd:一般来说,是活动窗口的句柄
* int len_x:位图的x方向的长(像素)
* int high_y:位图的y方向的高(像素)
* int start_x:需要截图位置的起始点坐标的x值
* int start_y:需要截图位置的起始点坐标的y值
* const wchar_t* abs_file_name:文件名字符串指针(以null结尾)
*/
int CaptureAnImage(HWND hWnd, int len_x, int high_y,int start_x,int start_y,const wchar_t* abs_file_name);

/*
* 获取并得到ocr识别的结果
* std::wstring& out:out参数,用于保存ocr的结果
* size_t str_len:实际需要的字符串长度
*/
bool get_ocr_result(std::wstring& out,size_t str_len) {
    system("C:\\Users\\gyj\\AppData\\Local\\Programs\\Tesseract-OCR\\tesseract D:\\工作\\temp\\2023年1月10日\\screenshot.bmp - -l eng --psm 7");
    CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo{};
    HANDLE consol_handle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (GetConsoleScreenBufferInfo(consol_handle, &lpConsoleScreenBufferInfo)) {
        COORD coord{ 0,0 };
        wchar_t buffer[32]{};
        DWORD char_num{};
        if (!ReadConsoleOutputCharacter(consol_handle, buffer, 4 * sizeof(TCHAR), coord, &char_num)) {
            std::cout << "读取结果错误:" << GetLastError();
            out.clear();
            return false;
        }
        else {
            out.clear();
            for (size_t i{}; i < char_num&&out.size()<= str_len; ++i) {
                if (buffer[i] >= L'0' && buffer[i] <= L'9') {
                    out.push_back(buffer[i]);
                }
            }
            if (out.size() < str_len) {
                return false;
            }
            return true;
        }
    }
    return false;
}
/*
* 输入验证码
* code:验证码字符串
*/
bool input_Verification_code(std::wstring& code) {
    move_left_clik_mouse(3300, 434);
    INPUT inputs[8]{};  //还必须在这儿分配好,不能使用堆
    
    for (size_t i{}, j{}; i < code.size() * 2; i += 2,++j) {
            inputs[i].type = INPUT_KEYBOARD;  //按下
            inputs[i].ki.wVk = key_vlaue[code[j]];
            inputs[i].ki.dwExtraInfo = GetMessageExtraInfo();
            
            inputs[i+1].type = INPUT_KEYBOARD;  //抬起
            inputs[i+1].ki.wVk = key_vlaue[code[j]];
            inputs[i+1].ki.dwFlags = KEYEVENTF_KEYUP;
            inputs[i+1].ki.dwExtraInfo = GetMessageExtraInfo();
    }
    UINT uSent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
    if (uSent != ARRAYSIZE(inputs))
    {
        std::cout << "验证码输入失败:" << HRESULT_FROM_WIN32(GetLastError());
        return false;
    }
    return true;
}
int main() {
    std::ios::sync_with_stdio(false);// 禁用同步
    std::locale::global(std::locale(""));    //本地化

    //应该尽量避免目标位置有变动。
    move_left_clik_mouse(3320, 550);
    HWND hWnd = GetForegroundWindow();    //获取活动窗口的句柄(因为鼠标点击过了,所以该窗口就是活动窗口)
    std::wstring result;
    size_t number_of_retries{};     //标记重复次数,大于10次之后,就停止识别
    do {
        CaptureAnImage(hWnd, 96, 31, 3192, 489, L"D:\\工作\\temp\\2023年1月10日\\screenshot.bmp");
        if (!get_ocr_result(result, 4)) {
            std::wcout << L"验证码识别出错\n";
            system("cls");
            move_left_clik_mouse(3246, 500);
            Sleep(100);
            move_left_clik_mouse(3400, 500);        //移开鼠标,否则影响识别
            Sleep(1000);
            number_of_retries++;
            if (number_of_retries > 10) {
                exit(0);
            }
        }
        else {
            std::wcout << result << L'\n';
            break;
        }
    } while(true);
    
    input_Verification_code(result);
    Sleep(500);
    move_left_clik_mouse(3320, 550);
    
}
int CaptureAnImage(HWND hWnd,int len_x,int high_y, int start_x, int start_y, const wchar_t* abs_file_name){
    HDC hdcScreen;
    HDC hdcWindow;
    HDC hdcMemDC = nullptr;
    HBITMAP hbmScreen = nullptr;
    BITMAP bmpScreen;
    DWORD dwBytesWritten = 0;
    DWORD dwSizeofDIB = 0;
    HANDLE hFile = nullptr;
    char* lpbitmap = nullptr;
    HANDLE hDIB = nullptr;
    DWORD dwBmpSize = 0;

    //检索窗口客户区的显示设备上下文句柄。
    hdcScreen = GetDC(nullptr);
    hdcWindow = GetDC(hWnd);

    // 创建一个兼容的 DC,它在来自窗口 DC 的 BitBlt 中使用。
    hdcMemDC = CreateCompatibleDC(hdcWindow);
    if (!hdcMemDC)
    {
        MessageBox(hWnd, L"CreateCompatibleDC has failed", L"Failed", MB_OK);
        goto done;
    }

    /* 获取客户区进行尺寸计算。
    RECT rcClient;
    GetClientRect(hWnd, &rcClient);
    这是最好的拉伸模式。
    SetStretchBltMode(hdcWindow, HALFTONE);
    源DC是整个屏幕,目标DC是当前窗口(HWND)。
    StretchBlt 函数将一个位图从源矩形复制到目标矩形中,并拉伸或压缩位图以适应目标矩形的尺寸(如有必要)。 系统根据当前在目标设备上下文中设置的拉伸模式拉伸或压缩位图。
    if (!StretchBlt(hdcWindow,
        0, 0,
        rcClient.right, rcClient.bottom,
        hdcScreen,
        0, 0,
        GetSystemMetrics(SM_CXSCREEN),
        GetSystemMetrics(SM_CYSCREEN),
        SRCCOPY))
    {
        MessageBox(hWnd, L"StretchBlt has failed", L"Failed", MB_OK);
        goto done;
    }*/

    // 从 Window DC 创建一个兼容的位图。
    hbmScreen = CreateCompatibleBitmap(hdcWindow, len_x, high_y);

    if (!hbmScreen)
    {
        MessageBox(hWnd, L"CreateCompatibleBitmap Failed", L"Failed", MB_OK);
        goto done;
    }

    // 选择兼容位图到兼容内存DC。
    SelectObject(hdcMemDC, hbmScreen);

    // 位块传输到我们的兼容内存 DC。
    if (!BitBlt(hdcMemDC,
        0, 0,
        len_x, high_y,  //避免边缘部分导致识别错误
        //100,200,
        hdcWindow,        
        start_x, start_y,
        SRCCOPY))
    {
        MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
        goto done;
    }

    // 从 HBITMAP 中获取 BITMAP。
    GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);

    BITMAPFILEHEADER   bmfHeader;
    BITMAPINFOHEADER   bi;

    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = bmpScreen.bmWidth;
    bi.biHeight = bmpScreen.bmHeight;
    bi.biPlanes = 1;
    bi.biBitCount = 32;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrUsed = 0;
    bi.biClrImportant = 0;

    dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;

    // 从 32 位 Windows 开始,GlobalAlloc 和 LocalAlloc 被实现为使用进程默认堆的句柄调用 HeapAlloc 的包装函数。 因此,GlobalAlloc 和 LocalAlloc 的开销比 HeapAlloc 大。
    hDIB = GlobalAlloc(GHND, dwBmpSize);
    lpbitmap = (char*)GlobalLock(hDIB);

    // 从位图中获取“位”,并将它们复制到 lpbitmap 指向的缓冲区中。
    GetDIBits(hdcWindow, hbmScreen, 0,
        (UINT)bmpScreen.bmHeight,
        lpbitmap,
        (BITMAPINFO*)&bi, DIB_RGB_COLORS);

    // 创建一个文件,这是我们将保存屏幕截图的地方。
    hFile = CreateFile(//L"captureqwsx.bmp",
        abs_file_name,
        GENERIC_WRITE,
        0,
        nullptr,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL, nullptr);
    if (INVALID_HANDLE_VALUE == hFile) {
        std::cout << "文件句柄创建失败:" << GetLastError();
    }
    // 将标头的大小添加到位图的大小以获得总文件大小。
    dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    // 偏移到实际位图位开始的位置。
    bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

    // 文件的大小。
    bmfHeader.bfSize = dwSizeofDIB;

    // 对于位图,bfType 必须始终为 BM。
    bmfHeader.bfType = 0x4D42; // BM.

    WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, nullptr);
    WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, nullptr);
    WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, nullptr);

    // 从堆中解锁并释放 DIB。
    GlobalUnlock(hDIB);
    GlobalFree(hDIB);

    // 关闭已创建文件的句柄。
    CloseHandle(hFile);

    // 清理。
done:
    DeleteObject(hbmScreen);
    DeleteObject(hdcMemDC);
    ReleaseDC(nullptr, hdcScreen);
    ReleaseDC(hWnd, hdcWindow);

    return 0;
}
View Code

这一堆主要的功能是,识别验证码并输入后登陆系统。

标签:inputs,ListNode,鼠标,单击,int,mi,识图,next,ocr
From: https://www.cnblogs.com/love-DanDan/p/17160585.html

相关文章