C ++ очередь буфера обмена, вставляющая случайные результаты? - PullRequest
0 голосов
/ 21 января 2020

Я пытаюсь создать очередь из буфера обмена, позволяя мне копировать несколько вещей, а затем вставлять их в FIFO. Для этого я использую Windows API, а также базовую c клавиатуру для обнаружения клавиш ctrl + c и ctrl + v. Кажется, мой код работает, но я, кажется, постоянно получаю случайный вывод из очереди.

#include <Windows.h>
#include <stdio.h>
#include <vector> 


using namespace std;
vector<char*> clipboardQueue; 
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
    if (wParam == WM_KEYDOWN) {
        if (p->vkCode == 0x43 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-c is pressed
            WM_COPY;
            Sleep(500);
            OpenClipboard(NULL);
            char* buffer;
            buffer = (char*)GetClipboardData(CF_TEXT);
            CloseClipboard();
            clipboardQueue.push_back(buffer);
            cout << buffer << " copied!\n";
            cout << "clipboard size: " << clipboardQueue.size() << "\n";
        }
        else if (p->vkCode == 0x56 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-v is pressed
            if (clipboardQueue.size() > 0) {
                const char* output = clipboardQueue[0];
                const size_t len = strlen(output) + 1;
                HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
                memcpy(GlobalLock(hMem), output, len);
                GlobalUnlock(hMem);
                OpenClipboard(0);
                EmptyClipboard();
                SetClipboardData(CF_TEXT, hMem);
                CloseClipboard();
                WM_PASTE;
                clipboardQueue.erase(clipboardQueue.begin());
                cout << output << " pasted!\n";
                cout << "clipboard size: " << clipboardQueue.size() << "\n";
            }
        }

    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

int main()
{
    OpenClipboard(NULL);
    EmptyClipboard();
    CloseClipboard();
    HHOOK keyBoard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, NULL);
    MSG msg;

    while (GetMessage(&msg, NULL, NULL, NULL)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    UnhookWindowsHookEx(keyBoard);
}

Использование этого кода при копировании «один, два, три, четыре, пять» мои выходные данные кажутся случайными с время от времени пропадают ключи:


три три три? пять


один? три ? пять


? четыре четыре четыре пять

1 Ответ

0 голосов
/ 23 января 2020

Ключевые правки:

  1. При копировании данных в буфер обмена с помощью ctrl + c будет отправлено сообщение WM_CLIPBOARDUPDATE, которое вы можете использовать для мониторинга ctrl + c операций . Но нет никакого связанного сообщения, чтобы контролировать операцию вставки control + v, поэтому я оставляю зацепку для control + v.
  2. Я могу воспроизвести "выходные данные кажутся случайными" проблемой и решить ее, используя массив вместо std::vector.
  3. Создайте окно только для сообщений , если вам не нужен интерактивный интерфейс.
  4. Добавьте новый пользовательский формат буфера обмена MY_CLIPBOARD_FORMAT, чтобы указать, что установлен набор данных WM_CLIPBOARDUPDATE сообщение не актуально control + v операция.

Следующее является лишь примером реализации вашего варианта использования, к которому вы можете обратиться:

#include <windows.h>

#define MAX_LOADSTRING 100
#define MY_CLIPBOARD_FORMAT (CF_PRIVATEFIRST + 1)

// Global Variables:
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
static int index = 0;
static char dataArry[10][10] = {};


// Forward declarations of functions included in this code module:
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK LowLevelKeyboardProc(int, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    DWORD errorCode;

    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_QUEUECLIPBOARDDATA, szWindowClass, MAX_LOADSTRING);

    // Register window class
    WNDCLASSEXW wcex = {};
    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.lpfnWndProc = WndProc;
    wcex.hInstance = hInstance;
    wcex.lpszClassName = szWindowClass;

    ATOM cls = RegisterClassExW(&wcex);
    errorCode = GetLastError();
    // Create a message-only window
    HWND hWnd = CreateWindowEx(0, szWindowClass, szTitle, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);

    if (!hWnd)
    {
        errorCode = GetLastError();
        return FALSE;
    }

    // Set keyboard hook
    HHOOK keyBoard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, NULL);

    // Register a clipboard format listener 
    if (!AddClipboardFormatListener(hWnd))
        errorCode = GetLastError();


    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
    PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
    if (wParam == WM_KEYDOWN) {
        if (p->vkCode == 0x56 && GetKeyState(VK_CONTROL) & 0x8000) { // ctrl-v is pressed

            if(index <= 0)
                return CallNextHookEx(NULL, nCode, wParam, lParam);

            static int i = 0;
            if (i < index)
            {
                const char* output = dataArry[i];
                const size_t len = strlen(output) + 1;
                HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len);
                memcpy(GlobalLock(hMem), output, len);
                GlobalUnlock(hMem);
                OpenClipboard(0);
                EmptyClipboard();
                SetClipboardData(CF_TEXT, hMem);

                // Set custom defined format to indicate paste operation
                SetClipboardData(MY_CLIPBOARD_FORMAT, NULL);
                CloseClipboard();
                OutputDebugStringA("\n pasted!\n");
                i++;
            }
            else
            {
                i = 0;
                index = 0;
            }
        }

    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    DWORD errorCode;
    HANDLE clipObj = NULL;
    char* lptstr = NULL;

    switch (message)
    {
    case WM_CLIPBOARDUPDATE:
        {
            OutputDebugStringA("\nWM_CLIPBOARDUPDATE\n");

            // Empty clipboard casue this WM_CLIPBOARDUPDATE, actually no new data copied
            if (IsClipboardFormatAvailable(MY_CLIPBOARD_FORMAT))
                break;

            if (!IsClipboardFormatAvailable(CF_TEXT))
                break;

            if (!OpenClipboard(hWnd))
            {
                errorCode = GetLastError();
                break;
            }

            clipObj = GetClipboardData(CF_TEXT);
            if(NULL == clipObj)
            {
                errorCode = GetLastError();
                break;
            }

            lptstr = (char*)GlobalLock(clipObj);
            if (lptstr != NULL)
            {
                OutputDebugStringA(lptstr);

                memcpy(dataArry[index++], lptstr, strlen(lptstr));

                GlobalUnlock(lptstr);
            }
            CloseClipboard();
        }
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
...