Как строится LPARAM для PostMessage ()? - PullRequest
0 голосов
/ 11 февраля 2019

У меня проблемы с параметром LPARAM в PostMessage ().

Это широко доступный пример того, как буква z набирается с помощью PostMessage ():

PostMessage(handle, WM_KEYDOWN, 0x5A, 0x002C0001) // key down for z
PostMessage(handle, WM_KEYUP, 0x5A, 0xC02C0001) // key up for z

Чтотакое формула для получения LPARAM "0x002C0001" для нажатия клавиши и "0xC02C0001" для нажатия клавиши вверх?Я хочу повторить это для всех ключей. Возможно ли создать две функции, скажем, CreateLPARAM_KeyDown () и CreateLPARAM_KeyUp (), где вы просто передаете код сканирования - или, что еще лучше, код виртуального ключа, независимого от устройства, - и они возвращают LPARAM?

С keybd_event () это намного проще, вы просто оставляете параметр dwFlags 0 для нажатия клавиши и используете KEYEVENTF_KEYUP для нажатия клавиши вверх, но окно должно иметь фокус, а окно, которое я отправляю, находится в фоновом режиме,поэтому keybd_event () и SendInput () в моем случае бесполезны.

Ответы [ 3 ]

0 голосов
/ 11 февраля 2019

Я бы предложил использовать для этой цели SendInput API.

Так что вам просто нужно заполнить соответствующую KEYBDINPUT структуру, которая хорошо документирована.

0 голосов
/ 12 февраля 2019

Возможно ли создать две функции, скажем, CreateLPARAM_KeyDown () и CreateLPARAM_KeyUp (), где вы просто передаете код сканирования - или, что еще лучше, код виртуального ключа, независимого от устройства, - и они возвращают LPARAM?

Попробуйте что-то вроде этого:

std::pair<USHORT, bool> VirtualKeyToScanCode(UINT VirtualKey)
{
    USHORT ScanCode = (USHORT) MapVirtualKey(VirtualKey, MAPVK_VK_TO_VSC);
    bool IsExtended = false;

    // because MapVirtualKey strips the extended bit for some keys
    switch (VirtualKey)
    {
        case VK_RMENU: case VK_RCONTROL:
        case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN: // arrow keys
        case VK_PRIOR: case VK_NEXT: // page up and page down
        case VK_END: case VK_HOME:
        case VK_INSERT: case VK_DELETE:
        case VK_DIVIDE: // numpad slash
        case VK_NUMLOCK:
        {
            IsExtended = true;
            break;
        }
    }

    return std::make_pair(ScanCode, IsExtended);
}

LPARAM CreateLPARAM_KeyUpDown(UINT VirtualKey, USHORT RepeatCount, bool TransitionState, bool PreviousKeyState, bool ContextCode)
{
    std::pair<USHORT, bool> ScanCode = VirtualKeyToScanCode(VirtualKey);
    return (
        (LPARAM(TransitionState) << 31) |
        (LPARAM(PreviousKeyState) << 30) |
        (LPARAM(ContextCode) << 29) |
        (LPARAM(ScanCode.second) << 24) |
        (LPARAM(ScanCode.first) << 16) |
        LPARAM(RepeatCount)
    );
}

LPARAM CreateLPARAM_KeyDown(UINT VirtualKey, USHORT RepeatCount = 1)
{
    return CreateLPARAM_KeyUpDown(VirtualKey, RepeatCount, false, RepeatCount > 1, false);
}

LPARAM CreateLPARAM_KeyUp(UINT VirtualKey)
{
    return CreateLPARAM_KeyUpDown(VirtualKey, 1, true, true, false);
}
0 голосов
/ 11 февраля 2019

Значение LPARAM и WPARAM варьируется для конкретного обрабатываемого сообщения.Вот почему документация для PostMessage не может быть слишком специфичной для этих параметров, а только:

Дополнительная информация, специфичная для сообщения.

На обоих.Чтобы точно знать, что они означают для каждого сообщения, вам нужно посмотреть документацию к этому сообщению.

В случае сообщений, о которых вы спрашиваете, WM_KEYUP и WM_KEYDOWN, значение LPARAM указывает:

Счетчик повторений, код сканирования, расширенный ключфлаг, код контекста, предыдущий флаг состояния ключа и флаг переходного состояния, как показано в следующей таблице.(Источник # 1 , # 2 )

Bits    Meaning
0-15    The repeat count for the current message. The value is the number of times the keystroke is autorepeated as a result of the user holding down the key. 
16-23   The scan code. The value depends on the OEM.
24      Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25-28   Reserved; do not use.
29      The context code. 
30      The previous key state. 
31      The transition state.

Давайте рассмотрим биты для вашего WM_KEYDOWN LPARAM там:

0x002C0001

0b0000000000101100000000000001

Устанавливаются биты 21, 19, 18 и 0. Это говорит нам о том, что:

Количество повторений равно 1

Остальные биты являются кодом сканирования для z, который явно равен 0b00101100 или 0x2C.

Сообщение WM_KEYUP имеет значение LPARAM 0xC02C0001, которое отличается только при самом значительном nybble, давая нам:

0b1100000000101100000000000001

Итак,единственное отличие здесь состоит в том, что биты предыдущего состояния и состояния перехода равны 1, что в любом случае гарантировано для сообщения WM_KEYUP.

Что касается другого вашего вопроса:

Можно ли создать две функции, скажем, CreateLPARAM_KeyDown () и CreateLPARAM_KeyUp (), где вы просто передаете код сканирования?

Конечно.Посмотрите на MapVirtualKey, чтобы определить, как получить код сканирования из кода ключа, и использовать битовые операции для создания 32-битного LPARAM из этого и всего остального, что вы знаете из таблицы выше обиты, которые должны быть установлены для этих сообщений.Для этого вам потребуется использовать битовое смещение и другие битовые операции, поскольку код сканирования представляет собой один 8-битный байт, который хранится как часть 32-битного LPARAM.

...