Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Hook, клава, и прикол 
:(
    Опции темы
OXOTHUK
Дата 10.8.2006, 10:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Я тут делаю Jokewar`ную прогу через Hook`и для клавиатуры. Я считываю состояние клавиш через GetKeyboardState. Мне нужно определённую кнопку "подменить" другой, например пользователь нажал "ч", а нажалось "ш". Как это можно организовать? Может лучше использовать что-то другое, а не GetKeyboardState. Видел, что-то похожее на дельфе, они там получали HWND через lParam(в функции хуков 3 параметра int, lparam, wparam) так: TMsg(Pointer(lParam)^).hwnd, как так сделать в MSVS я не знаю. Пробывал читать GetKeyboardState, а вписывать через SetKeyboardState, но ничего не получилось.
PM MAIL   Вверх
_hunter
Дата 10.8.2006, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

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



веашй обычный хук (WH_KEYBOARD).
и в его обработчике просто меняй wParam (virtual-key code)

Добавлено @ 10:50 
http://www.realcoding.net/article/view/182


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
OXOTHUK
Дата 10.8.2006, 15:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Я менял, но мои изменения не сохраняются, т. е. продолжает печататься то что нажал. Я проверки вывожу мессагбоксом, там меняется, а в окошке не печатается. Как буд-то на wParam стоит const. Есть ещё методы?
PM MAIL   Вверх
_hunter
Дата 10.8.2006, 16:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

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



ты цепочку продолжаеш?
в любом случае -- показывай код


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
0x07L
Дата 10.8.2006, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Делал такую прогу месяц назад. Успешно.
PM MAIL   Вверх
Sheff
Дата 10.8.2006, 20:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 503
Регистрация: 25.3.2002
Где: Зеленоград

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



OXOTHUK, делал похожую прогу с подменой ввода мышки, с клавой аналогично, если нужно могу выслать сорс, пиши в асю 135394514.


--------------------
--------------------------
Шеф всегда прав :)
PM MAIL WWW ICQ   Вверх
OXOTHUK
Дата 11.8.2006, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Вот мой код(dll):
Код

#include <windows.h>
#include <shlobj.h>
#include <stdlib.h>
#include <stdio.h>

LRESULT __stdcall SysMsgHook(int code, WPARAM wParam, LPARAM lParam);

inline bool Get30Bit(LPARAM val) { return val&0x40000000;}

int VkToChar(UINT vk,LPWORD ret)
{
    char kb[256];
    GetKeyboardState((PBYTE)kb);
    return ToAscii(vk, 0, (PBYTE)kb, ret, 0);
}

HHOOK SysHook;
HINSTANCE hInstance;

extern "C" __declspec(dllexport) void SetHook(bool State);

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    hInstance = (HINSTANCE)hModule;
    return TRUE;
}

void SetHook(bool State)
{
    if(State) SysHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)SysMsgHook, hInstance, 0);
    else
    {
        UnhookWindowsHookEx(SysHook);
        SysHook = 0;
    }
}

LRESULT __stdcall SysMsgHook(int code, WPARAM wParam, LPARAM lParam)
{
    if(code==HC_ACTION)
    { 
        if(Get30Bit(lParam))
                {
                    WORD ret;
                        if(VkToChar(wParam,&ret))
                        {
                if (wParam==88) wParam = 89;//ч меняю на ш
//почемуто все коды, независимо от раскладки идут в больших английских буквах
                char key[2] = {wParam, '\0'};
                MessageBox(NULL, key, "", MB_OK);
            }
        }
    }
    return CallNextHookEx(SysHook, code, wParam, lParam) ;
}

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


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 8564
Регистрация: 24.6.2003
Где: Europe::Ukraine:: Kiev

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



что-то я не заметил в коде изменения wParam...


--------------------
Tempora mutantur, et nos mutamur in illis...
PM ICQ   Вверх
Sheff
Дата 11.8.2006, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 503
Регистрация: 25.3.2002
Где: Зеленоград

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



OXOTHUK, ты изменил локальную переменную wParam не более и вообще лучше по другому сделать, подавлять ввод вообще, а вместо него посылать свой при помощи SendInput.


--------------------
--------------------------
Шеф всегда прав :)
PM MAIL WWW ICQ   Вверх
OXOTHUK
Дата 11.8.2006, 15:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Sheff, А как подавить? И напишите примерчик на SendInput(никогда не имел дела), plz.
PM MAIL   Вверх
0x07L
Дата 11.8.2006, 18:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Знаю, что просили не меня, но все же:
Код

LRESULT CALLBACK LowLevelKeyboardHookProc(const int code, const WPARAM wparam, const LPARAM lparam)
{
    if (Running && code == HC_ACTION)
    {
        LPKBDLLHOOKSTRUCT pKeyboardHookInfo = reinterpret_cast<LPKBDLLHOOKSTRUCT>(lparam);
        
        if (pKeyboardHookInfo->dwExtraInfo == 666)
        {
            // это наше сообщение, пропускаем
            return CallNextHookEx(hHook, code, wparam, lparam);
        }

        KeyStruct key (pKeyboardHookInfo->scanCode, pKeyboardHookInfo->flags & LLKHF_EXTENDED);

        if (MapVirtualKey(pKeyboardHookInfo->scanCode, 1) == VK_SHIFT)
            // почему-то в случае правого Shift'а флаг расширенной клавиши устанавливается в true,
            // хотя этого, согласно страничке About Keyboard Input в MSDN, быть не должно;
            // тем более, скан-коды левого и правого Shift'ов различаются;
            // восстанавливаем справедливость
        {
            key.Extended = false;
        }
        
        if (key == SpecialKey)
        {
            OnSpecialKeyStopRunning();
            Running = false;
            return TRUE;
        }
        
        KeyConfigMap::const_iterator iter = KeyConfig.find(key);
        if (iter != KeyConfig.end())
        {
            KeyStruct key = iter->second; // GetSpecialValue не константу
            unsigned int specialValue = key.GetSpecialValue();
            if (specialValue == DeleteKey)
            {
                return TRUE; // удаляем клавишу
            }
            else if (specialValue == 0)
            {
                if (MapVirtualKey(pKeyboardHookInfo->scanCode, 1) == VK_MENU)
                    // 1 - перевести скан-код в виртуальный код, не различая левых и правых клавиш
                    // если нажат Alt (левый или правый), шлем соответствующий ввод
                {
                    INPUT input;
                    input.type = INPUT_KEYBOARD;
                    input.ki.wVk = 0;
                    input.ki.wScan = static_cast<WORD>(pKeyboardHookInfo->scanCode);
                    input.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
                    input.ki.time = 0;
                    input.ki.dwExtraInfo = 666; // это наше сообщение
                    SendInput(1, &input, sizeof input);
                }
                
                INPUT input;
                input.type = INPUT_KEYBOARD;
                input.ki.wVk = 0;
                input.ki.wScan = iter->second.ScanCode;
                input.ki.dwFlags = KEYEVENTF_SCANCODE;
                if (iter->second.Extended)
                {
                    input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
                }
                if (pKeyboardHookInfo->flags & LLKHF_UP)
                {
                    input.ki.dwFlags |= KEYEVENTF_KEYUP;
                }
                input.ki.time = 0;
                input.ki.dwExtraInfo = 666; // это наше сообщение
                SendInput(1, &input, sizeof input);

                return TRUE;
            }
        }
    }
    return CallNextHookEx(hHook, code, wparam, lparam);
}

1) Есть загвоздка: то, что мы шлем с помощью SendInput, тоже обрабатывается хуком. Для этого придумано спец. значение 666.

2) KeyStruct - это просто структура, которая может хранить скан-код и флажок Extended, а также два специальных значения.
    Одно из них я использую, если клавиша должна быть удалена, а не замещена.

3) KeyConfigMap - это тип (объявлен через typedef) std::map с нужными мне аргументами шаблона

4) KeyConfig - это глобальный объект типа KeyConfigMap, где хранится конфигурация - пары клавиш 
    [клавиша, кот. заменить] - [клавиша, на кот. заменить]
    Как я уже сказал, вторая клавиша может иметь специальное значение (удалить).
    Каждый раз мы ищем нажатую клавишу в этой конфигурации

5) Еще загвоздка. Если нажат Alt - мы "отпускаем" его, посылая key up. Без этого будут глюки.
    Alt - вредная клавиша. С Ctrl и Shift все нормально.

Если чего-то еще непонятно, спрашивай. Надеюсь, ты найдешь для себя здесь что-то полезное.

Добавлено @ 18:19 
Чуть не забыл: MapVirtualKey - это полезная стандартная функция.
PM MAIL   Вверх
Sheff
Дата 11.8.2006, 18:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 503
Регистрация: 25.3.2002
Где: Зеленоград

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



Код

INPUT inp1,inp2;

    inp1.type=INPUT_MOUSE;
    inp1.mi.dx=0;
    inp1.mi.dy=0;
    inp1.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    inp1.mi.mouseData = 0;
    inp1.mi.dwExtraInfo = 0;

    inp2.type=INPUT_MOUSE;
    inp2.mi.dx=0;
    inp2.mi.dy=0;
    inp2.mi.dwFlags = MOUSEEVENTF_LEFTUP;
    inp2.mi.mouseData = 0;
    inp2.mi.dwExtraInfo = 0;

SendInput(1,&inp1,sizeof(INPUT));
SendInput(1,&inp2,sizeof(INPUT));
}
Вот имитация клика мышкой, для клавы там всё тоже просто, в MSDN'е есть, почитай. А подавление ввода, думаю с WH_CBT хуком надо играться, щас просто времени нет, так бы посмотрел как именно надо это делать.


Добавлено @ 18:26 
OXOTHUK, похоже тебе уже всё написали добрые люди smile


--------------------
--------------------------
Шеф всегда прав :)
PM MAIL WWW ICQ   Вверх
0x07L
Дата 12.8.2006, 08:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Кстати, это функция хука WH_KEYBOARD_LL
PM MAIL   Вверх
OXOTHUK
Дата 12.8.2006, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



0x07L, А где объявлены(или описаны типы):
DeleteKey
KeyStruct
SpecialKey
Running
KeyConfigMap?

Где можно подменить клавишу? (а то тут стоко всего)

И у меня при компиляции, те переменные, которые объявлены в winuser.h(даже если он включен) говорит что андекларед инедтифаер. Глюк, что ли?
PM MAIL   Вверх
0x07L
Дата 12.8.2006, 12:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Это все мое  smile Так уж и быть, переделаю код конкретно для тебя.
Код

LRESULT CALLBACK LowLevelKeyboardHookProc(const int code, const WPARAM wparam, const LPARAM lparam)
{
    if (code == HC_ACTION)
    {
        LPKBDLLHOOKSTRUCT pKeyboardHookInfo = reinterpret_cast<LPKBDLLHOOKSTRUCT>(lparam);
        
        if (pKeyboardHookInfo->dwExtraInfo == 666)
        {
            // это наше сообщение, пропускаем
            return CallNextHookEx(hHook, code, wparam, lparam);
        }

        bool Extended = (pKeyboardHookInfo->flags & LLKHF_EXTENDED);

        if (MapVirtualKey(pKeyboardHookInfo->scanCode, 1) == VK_SHIFT)
            // почему-то в случае правого Shift'а флаг расширенной клавиши устанавливается в true,
            // хотя этого, согласно страничке About Keyboard Input в MSDN, быть не должно;
            // тем более, скан-коды левого и правого Shift'ов различаются;
            // восстанавливаем справедливость
        {
            Extended = false;
        }
        
        if (MapVirtualKey(pKeyboardHookInfo->scanCode, 1) == 41
                && Extended == false)
        // замени 41 на виртуальный код клавиши, которую хочешь заменить (не Alt);
        // здесь 41 для примера - виртуальный код клавиши 'A' (латинской, естественно);
        //
        // false замени на true, если твоя клавиша - расширенная;
        // Cм. страничку "About Keyboard Input" в MSDN.
        {                
                INPUT input;
                input.type = INPUT_KEYBOARD;
                input.ki.wVk = 42;
                // замени 42 на виртуальный код клавиши, _НА_ которую хочешь заменить;
                // здесь 42 для примера - виртуальный код клавиши 'B' (латинской, естественно)
                input.ki.wScan = 0;
                input.ki.dwFlags = 0;
                if (false)
                // эта конструкция только для примера :-) Никогда не используй "if (false)" :-);
                // замени false на true, если клавиша, _НА_ которую хочешь заменить, расширенная
                {
                    input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
                }
                if (pKeyboardHookInfo->flags & LLKHF_UP)
                {
                    input.ki.dwFlags |= KEYEVENTF_KEYUP;
                }
                input.ki.time = 0;
                input.ki.dwExtraInfo = 666; // это наше сообщение
                SendInput(1, &input, sizeof input);

                return TRUE;
            }
        }
    }
    return CallNextHookEx(hHook, code, wparam, lparam);
}

Виртуальные коды клавиш смотри в MSDN на страничке "Virtual-Key Codes".
Код набирал здесь, поэтому за его работоспособность не ручаюсь.
Еще. Я не тестил это на клавиатурах с медиа-клавишами (нет такой клавиатуры в наличии).

Это сообщение отредактировал(а) 0x07L - 12.8.2006, 12:18
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

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


 




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


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

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