Модераторы: Rickert, Alexeis, BorisVorontsov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Эмуляция нажатий клавиш в DirectX приложении 
V
    Опции темы
Jr13san
Дата 18.9.2011, 19:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 29.7.2008
Где: г. Павлово

Репутация: нет
Всего: нет



Цитирую один вопрос с другого форума:
Цитата
Бьюсь над следущей проблемой, как можно проэмулировать нажатие кнопки на клавиатуре для приложения, использующее DirectInput

keyb_event'ом не получается. Т. к. DirectX игнорирует все win сообщения.

У кого есть какие соображения?

У меня такая же задача. На том форуме ответа не было дано. Может быть здесь найдутся люди, которые могут помочь в проблеме?

Результат данной темы прикреплён ниже:

Это сообщение отредактировал(а) Jr13san - 11.11.2011, 18:10

Присоединённый файл ( Кол-во скачиваний: 189 )
Присоединённый файл  DXKeyHelp.rar 204,23 Kb
PM MAIL WWW ICQ   Вверх
bems
Дата 18.9.2011, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 1
Всего: 88



SendInput, используя сканкоды (флаг KEYEVENTF_SCANCODE в структуре KEYBDINPUT)

Это сообщение отредактировал(а) bems - 18.9.2011, 21:16


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Jr13san
Дата 19.9.2011, 09:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 29.7.2008
Где: г. Павлово

Репутация: нет
Всего: нет



Даже такая конструкция не работает там. В блокноте норм печатает TAB, а в том приложении 0 реакций.
Может быть там сообщения принимаются с формы, которая в full screen режиме?

Код

#include <windows.h>//API функции
#include <iostream>
using namespace std;

void GenerateKey(BYTE vk)
{

    INPUT Input;
    ZeroMemory(&Input, sizeof(Input));
    Input.type = INPUT_KEYBOARD;
    Input.ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
    Input.ki.wVk = vk;
    SendInput(1, &Input, sizeof(INPUT));

    return;
}

void main()
{
    bool dowork = TRUE;
    while(dowork == TRUE)
    {
        if(GetAsyncKeyState(52))//если нажата цифра 4, то
        {
            GenerateKey((UCHAR)VkKeyScan(VK_TAB));//создаём нажатие TAB
        }
        Sleep(150);
    }
}

PM MAIL WWW ICQ   Вверх
bems
Дата 19.9.2011, 10:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 1
Всего: 88



Цитата(bems @  18.9.2011,  21:14 Найти цитируемый пост)
используя сканкоды

Цитата(bems @  18.9.2011,  21:14 Найти цитируемый пост)
KEYEVENTF_SCANCODE


Это сообщение отредактировал(а) bems - 19.9.2011, 10:42


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Jr13san
Дата 19.9.2011, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 29.7.2008
Где: г. Павлово

Репутация: нет
Всего: нет



bems, в смысле используя сканкоды"?
Ни так:
Код

Input.ki.wScan = KEYEVENTF_SCANCODE;

Ни так:
Код

Input.ki.dwFlags = KEYEVENTF_SCANCODE;

не работает.
Я когда-то экспериментировал на других приложениях, но тогда работал на Visual Basic.
Там можно было посылать сигналы так:
Код

Private Sub Command1_Click()
AppActivate ("Безымянный")'активируем окно.
SendKeys ("Эй Блокнот, меня слышно?") 'Отсылаемый текст
End Sub

Т.е. вот эти команды:
Код

SendKeys ("Эй Блокнот, меня слышно?")'текст
SendKeys "{Enter}"'клавиша Enter
SendKeys "{Esc}"'клавиша Tab

А вот как на c++ послать эти сигналы в другое приложение?

Может быть мне нужно:
1) найти хэндл окна с помощью функции FindWindow()
2) послать сообщение с помощью функции SendMessage()

только как узнать хэндл окна, которому нужно посылать? Просто проблема в том, что у Главного окна может быть дочернее и фиг знает как оно называется, а у этого дочернего есть ещё 1 окно, в котором отображается вся графика. Поэтому тут тяжело даётся этот момент.

Мне бы посмотреть на примере калькулятора, как это всё работает, а там я попробовал бы сам.
Вот эмуляция нажатия кнопки "ПУСК"
Код

HWND hTaskBar, hButton;
    hTaskBar= FindWindow(L"Shell_TrayWnd",NULL);
    hButton= GetWindow(hTaskBar, GW_CHILD);
    // Hажать кнопку "Пуск"
    SendMessage(hButton, WM_LBUTTONDOWN,MK_LBUTTON,LOWORD(5));
    return;


Ну предположим хэндл окна я найду, а вот как послать нажатие кнопки клавиатуры 'q' через SendMessage я не пойму. Параметры усложняют всё.
bems, помоги пожалуйста разобраться хотя бы на простом примере калькулятора.

Чем Microsoft занимается? давным давно написали бы все эти процедуры, причём с глобальной точки зрения. А ты вот сидишь и думаешь, то ли там так посылается сигнал, то ли так. Как нибудь сделали бы через драйвера той же самой клавиатуры, а не через системные сообщения...

Цитата(Dem_max @  19.9.2011,  17:35 Найти цитируемый пост)
Попробуй послать комбинацию Alt+tab, полно экранная игра должна свернуться. Вот и проверит работает это сочетание.

Оно может и сработает, но это мне не надо. Мне нужно послать нажатие клавиши.

Это сообщение отредактировал(а) Jr13san - 19.9.2011, 20:06
PM MAIL WWW ICQ   Вверх
Dem_max
Дата 19.9.2011, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: нет
Всего: 39



Попробуй послать комбинацию Alt+tab, полно экранная игра должна свернуться. Вот и проверит работает это сочетание.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
bems
Дата 19.9.2011, 21:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 1
Всего: 88



так попробуй
Код

DWORD SendScanCode(WORD scan, BOOL up)
{
    INPUT inp = {0};
    inp.type = INPUT_KEYBOARD;
    inp.ki.wScan = scan;
    inp.ki.dwFlags = KEYEVENTF_SCANCODE | (up ? KEYEVENTF_KEYUP : 0); 
    return SendInput(1, &inp, sizeof(inp)) ? NO_ERROR : GetLastError();
}

DWORD SendVirtualKey(UINT vk, BOOL up)
{
    UINT scan = MapVirtualKey(vk, MAPVK_VK_TO_VSC);
    return scan ? SendScanCode(scan, up) : ERROR_NO_UNICODE_TRANSLATION;
}

DWORD SendChar(TCHAR ch, BOOL up)
{
    SHORT vk = VkKeyScan(ch);
    DWORD Result;
    if (0xFFFF == (USHORT)vk)
        Result = ERROR_NO_UNICODE_TRANSLATION; 
    else 
        if (up)
            Result = SendVirtualKey(LOBYTE(vk), TRUE); 
        else {
            Result = NO_ERROR;
            if (HIBYTE(vk) & 1) Result = SendVirtualKey(VK_LSHIFT,   FALSE);
        
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 2) Result = SendVirtualKey(VK_LCONTROL, FALSE);
        
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 4) Result = SendVirtualKey(VK_LMENU,    FALSE);
        
            if (NO_ERROR == Result) {
            Result = SendVirtualKey(LOBYTE(vk), FALSE);  
        
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 4) Result = SendVirtualKey(VK_LMENU,    TRUE);
        
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 2) Result = SendVirtualKey(VK_LCONTROL, TRUE);
        
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 1) Result = SendVirtualKey(VK_LSHIFT,   TRUE);
            }}}}}}
        }

    return Result;
}

DWORD SendString(LPCTSTR s) 
{
    DWORD Result = NO_ERROR;
    for (; *s && !Result; ++s) {
        Result = SendChar(s[0], FALSE);
        if (NO_ERROR == Result) Result = SendChar(s[0], TRUE);
    }
    return Result;
}



--------------------
Обижено школьников: 8
PM MAIL   Вверх
Jr13san
Дата 19.9.2011, 21:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 29.7.2008
Где: г. Павлово

Репутация: нет
Всего: нет



Код

void main()
{
    setlocale(LC_ALL, "Russian");//устанавливаем русский язык для вывода

    bool dowork = TRUE;
    while(dowork == TRUE)
    {
        if(GetAsyncKeyState(52))//если нажата цифра 4, то
        {
            SendVirtualKey(???,1);//создаём нажатие TAB
        }
        Sleep(150);
    }
}


??? - А что сюда подставить?
без знаковое число int..., но какое, как понять?
Например нужно для кнопки "q".

Это сообщение отредактировал(а) Jr13san - 19.9.2011, 22:07
PM MAIL WWW ICQ   Вверх
bems
Дата 19.9.2011, 22:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 1
Всего: 88



для ТАВа - SendVirtualKey(VK_TAB, FALSE);
для q - SendChar(_T('q'), FALSE);
для строки SendString(_T("Hello Here!"));

второй параметр истина, если это событие отпускания клавиши а не нажатия

Это сообщение отредактировал(а) bems - 19.9.2011, 22:17


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Jr13san
Дата 19.9.2011, 22:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 29.7.2008
Где: г. Павлово

Репутация: нет
Всего: нет



bems, благодарю, всё сработало.
Я был бы ещё очень больше благодарен, если бы вы подписали к коду небольшие комментарии.
Просто мне стыдно копировать код, не зная как он работает.

Я думаю это было бы полезно не только мне, но и тем, кто сюда набредёт.

С одной стороны это одностороннее приложение и что в нём не было бы написано, всё равно это мало кому интересно из модостроителей Готики. Им важнее функции, которые они используют, чтобы послать сигнал об эмуляции нажатий путём изменения значения в памяти.

Это сообщение отредактировал(а) Jr13san - 19.9.2011, 22:31
PM MAIL WWW ICQ   Вверх
bems
Дата 19.9.2011, 22:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 1
Всего: 88



вроде разжевал
Код

DWORD SendScanCode(WORD scan, BOOL up) 
// посылает нажатие или отпускание клавиши со сканкодом scan
// если up == TRUE то это событие отпускания, иначе нажатия
// возвращает NO_ERROR в случае успеха или код ошибки 
{
    INPUT inp = {0};
    inp.type = INPUT_KEYBOARD;
    inp.ki.wScan = scan;
    inp.ki.dwFlags = KEYEVENTF_SCANCODE | (up ? KEYEVENTF_KEYUP : 0); 
    return SendInput(1, &inp, sizeof(inp)) ? NO_ERROR : GetLastError();
}

DWORD SendVirtualKey(UINT vk, BOOL up)
// посылает нажатие или отпускание виртуальной клавиши с кодом vk
// если up == TRUE то это событие отпускания, иначе нажатия
// возвращает NO_ERROR в случае успеха или код ошибки   
{
    UINT scan = MapVirtualKey(vk, MAPVK_VK_TO_VSC);
    // конвертируем виртуальный код в сканкод

    return scan ? SendScanCode(scan, up) : ERROR_NO_UNICODE_TRANSLATION;
    // если конверсия не удалась, то возвращаем 
    // ERROR_NO_UNICODE_TRANSLATION, хоть это и не вполне точно описывает
    // произошедшее, но ты будешь знать что трансляция навернулась.
    // Если трансляция есть, то посылаем полученный сканкод
}

DWORD SendChar(TCHAR ch, BOOL up)
// посылает нажатие или отпускание клавиши с кодом символа ch
// если up == TRUE то это событие отпускания, иначе нажатия
// возвращает NO_ERROR в случае успеха или код ошибки 
{
    SHORT vk = VkKeyScan(ch);
    // конвертируем символ в код виртуальной клавиши

    DWORD Result;
    if (0xFFFF == (USHORT)vk) // если не вышло возвращаем ошибку
        Result = ERROR_NO_UNICODE_TRANSLATION; 
    else 
        if (up) // если это отпускание то игнорируем состояние shift, ctrl, alt
            Result = SendVirtualKey(LOBYTE(vk), TRUE); 
            // и посылаем отпускание полученного виртуального кода
        else {
            // если это нажатие то нужно учесть shift, ctrl, alt
            // анализируем старший байт и при необходимости посылаем 
            // виртуальные коды VK_LSHIFT, VK_LCONTROL, VK_LMENU соответственно

            Result = NO_ERROR;
            if (HIBYTE(vk) & 1) Result = SendVirtualKey(VK_LSHIFT,   FALSE);
        
            // каждый шаг продолжаем только если нет ошибки, иначе просто возвращаем её код
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 2) Result = SendVirtualKey(VK_LCONTROL, FALSE);
        
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 4) Result = SendVirtualKey(VK_LMENU,    FALSE);
        
            if (NO_ERROR == Result) {
            Result = SendVirtualKey(LOBYTE(vk), FALSE);  
            // посылаем нажатиме полученного виртуального кода
        
            // снова анализируем старший байт и при необходимости посылаем отпускания виртуальных
            // кодов VK_LSHIFT, VK_LCONTROL, VK_LMENU, нажатия которых мы послали выше
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 4) Result = SendVirtualKey(VK_LMENU,    TRUE);
        
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 2) Result = SendVirtualKey(VK_LCONTROL, TRUE);
        
            if (NO_ERROR == Result) {
            if (HIBYTE(vk) & 1) Result = SendVirtualKey(VK_LSHIFT,   TRUE);
            }}}}}}
        }

    return Result;
}

DWORD SendString(LPCTSTR s) 
// посылает последовательность нажатий/отпусканий символов строки s
// возвращает NO_ERROR в случае успеха или код ошибки 
{
    DWORD Result = NO_ERROR;
    for (; *s && !Result; ++s) {
    // идем по всем символам строки пока не получили ошибку

        Result = SendChar(s[0], FALSE);
        // посылаем нажатие каждого символа

        if (NO_ERROR == Result) Result = SendChar(s[0], TRUE);
        // и если нет ошибки, то его отпускание
    }
    return Result;
}



--------------------
Обижено школьников: 8
PM MAIL   Вверх
Jr13san
Дата 20.9.2011, 09:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 29.7.2008
Где: г. Павлово

Репутация: нет
Всего: нет



bems, спасибо, но ещё чуть-чуть:
Зачем при нажатии нужно учитывать shift, ctrl, alt?

И правда ли, если создать цикл, который будет постоянно посылать событие отпускания каждой клавише клавиатуры, то клавиатура заблокируется? Или же сначала будет обработано событие нажатия, а затем уже событие отпускания?
Я к чему всё это. Если потребуется заблокировать все действия кнопок пользователя на время проигрывания каких-либо действий в приложении. Вот. Т.е. с помощью этих функций можно было бы создать блокировку нажатий клавиш от пользователя?


PM MAIL WWW ICQ   Вверх
bems
Дата 20.9.2011, 15:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 1
Всего: 88



Цитата(Jr13san @  20.9.2011,  09:25 Найти цитируемый пост)
Зачем при нажатии нужно учитывать shift, ctrl, alt?
ну например ты хотел отправить заглавную букву. После вызова VkKeyScan в младшем байте результата будет тот же сканкод что и для прописной, потому что это одна клавиша, но в старшем будет установлен самый младший бит, что значит что этот сканкод нужно посылать при нажатом шифте, чтобы получить капс

Цитата(Jr13san @  20.9.2011,  09:25 Найти цитируемый пост)
И правда ли, если создать цикл, который будет постоянно посылать событие отпускания каждой клавише клавиатуры, то клавиатура заблокируется?
впервые слышу. Если что-то такое и есть, то скорее всего это из-за особенностей реализации и не обязано быть постоянным по в всех версиях винды и во всех прикладных программах. Я бы на это не расчитывал



--------------------
Обижено школьников: 8
PM MAIL   Вверх
Jr13san
Дата 20.9.2011, 16:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 29.7.2008
Где: г. Павлово

Репутация: нет
Всего: нет



Цитата(bems @  20.9.2011,  15:59 Найти цитируемый пост)
ну например ты хотел отправить заглавную букву. После вызова VkKeyScan в младшем байте результата будет тот же сканкод что и для прописной, потому что это одна клавиша, но в старшем будет установлен самый младший бит, что значит что этот сканкод нужно посылать при нажатом шифте, чтобы получить капс

Сейчас стало понятнее..

Цитата(bems @  20.9.2011,  15:59 Найти цитируемый пост)
Я бы на это не расчитывал

А не подскажете как это можно было бы сделать?
Может быть через API функции какие-то?

Вот например Winamp ловит горячую клавишу свою и убивает сигнал от неё, поэтому иногда нельзя использовать сигнал этой клавиши, например, в блокноте не прописывается символ. Кажется есть какая-то API, которая глобально отлавливает нажатые клавиши, у меня тоже как-то раз такое получилось в своей проге на VIsual Basic, но я не помню как...

Это сообщение отредактировал(а) Jr13san - 20.9.2011, 16:48
PM MAIL WWW ICQ   Вверх
bems
Дата 20.9.2011, 17:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 1
Всего: 88



хоткеи и глобальное отключение клавы это разные вещи. А глобальный перехват - третья разная вещь smile
И вообще, один топик - один вопрос


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Jr13san
Дата 20.9.2011, 17:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 29.7.2008
Где: г. Павлово

Репутация: нет
Всего: нет



Ок. Вопрос полностью решен.

bems, ещё раз благодарю вас за помощь. Я точно бы не додумался до таких функций в текущее время. Если лет через 5, то мб, но тогда уже было бы поздно.
PM MAIL WWW ICQ   Вверх
aalleexxaa
Дата 25.3.2012, 10:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 20.2.2011

Репутация: нет
Всего: нет



Здрасти! Как я понял из поста - "готовый экземпляр" приложения из архива должен при нажатии кнопки "1" отправлять кнопку  "TAB". В блокноте работает, а в двух 3D приложениях не заработало. Почему так может быть, вроде как "вопрос решен" или нет?
PM MAIL   Вверх
RDLNEO
Дата 3.3.2015, 01:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 2.12.2009

Репутация: нет
Всего: нет



ребята - мне тож помогите я вижу тут похожая тема


Помогите написать одну очень нужную и очень коротенькую программу.

Она должна запускаться по горячей клавише и совершать комбинацию ALT+TAB случайное число раз
например это случайное число от 3 до 150
будет лучше, чтобы я сам смог изменять максимум для случайного числа при запуске программы

- она может быть резидентной
- может и нет.

Но мне не ясен способ вызова не резидентной программы по горячей клавише (например F12)

просьба помочь с данной темой


взамен у меня есть миди пианино (сам писал на VB6.0  6 лет назад)
к сожалению - это не исходник, а исталлятор
вирусов нет!
СкачатьMidi_Rus.zip

Это сообщение отредактировал(а) RDLNEO - 3.3.2015, 01:10
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Вы можете найти полезным что...
Alexeis
Rickert
  • Английская документация по DirectX лежит где-то здесь.
  • Английская документация по OpenGL лежит где-то там.
  • Гейм-дев у нас обсуждают где-то тут

Ждём вас! С уважением, Alexeis, Rickert.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Мультимедия, OpenGL/DirectX | Следующая тема »


 




[ Время генерации скрипта: 0.2089 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.