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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как перехватить нажатие клавиши 
:(
    Опции темы
Iamme
Дата 1.7.2009, 20:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Добрый день!

Мы вообще то пишем на java, но программа должна выполнять действия по комбинации клавиш (на java не реализуемо), в связи с этим я пытаюсь пока написать простейший код на С++ с использованием WinApi, который выводит сообщение по нажатию клавиши (пока любой).

Получилось вот что: 
Код


#include "stdafx.h"
#include "rrr.h"
#include <stdio.h>
#include <windows.h>

// функция вхождений программы WinMain
int KeyboardProc(int nCode, DWORD wParam, DWORD lParam)
{

 switch(wParam)
  {
  case WM_KEYDOWN:
    MessageBox(NULL, NULL, NULL, 0);
   break;
  default:
      break;
  }
 
 return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance,
             HINSTANCE         hPrevInstance,
             LPSTR             lpCmdLine,
             int               nCmdShow)
{

  SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)&KeyboardProc, GetModuleHandle(NULL), 0);
  // цикл сообщений приложения
 
  MSG msg = {0};    // структура сообщения
  int iGetOk = 0;   // переменная состояния
  while ((iGetOk = GetMessage(&msg, NULL, 0, 0 )) != 0) // цикл сообщений
  {
    if (iGetOk == -1) return 3;  // если GetMessage вернул ошибку - выход
    TranslateMessage(&msg);    
    DispatchMessage(&msg);
  }
  return 0;  // возвращаем код завершения программы
}

Сообщение вроде выводится по нажатию любой кнопки в любом окне, но сразу же возникает исключение "ошибка чтения"

Подскажите, в чем дело?

Также буду благодарна, если мне подскажут, как перехватывать не любую клавишу, а комбинацию Ctrl+C+C.

Спасибо.
Использую среду Visual C++.

PM MAIL   Вверх
GremlinProg
Дата 1.7.2009, 20:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



у KeyboardProc соглашение вызова должно быть stdcall
поправь так:
Код

int CALLBACK KeyboardProc(int nCode, DWORD wParam, DWORD lParam)


Добавлено через 3 минуты и 58 секунд
три клавиши...
вообще, на 3 разные клавиши можно обойтись GetKeyState
но раз некоторые повторяются, причем в определенной последовательности,
то можно завести стек последних трех клавиш (вернее очередь)


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
jonie
Дата 1.7.2009, 20:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



1.
Код

int __stdcall KeyboardProc(int nCode, DWORD wParam, DWORD lParam)


2.
Код

    default:
        break;
    }

    return CallNextHookEx(hhk, nCode, wParam, lParam);

...
hhk = SetWindowsHookEx
где hhk имеет тип HHOOK и является глобальной по отношению к функциям.

проверить на "ctrl" нажата можно так:
Код
if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) нажата





--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
Iamme
Дата 3.7.2009, 16:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



решение с перехватом пока такое

Код

#include "stdafx.h"
#include "rrr.h"
#include <stdio.h>
#include <windows.h>
#define VK_C    0x043

HHOOK hHook;
// функция вхождений программы WinMain
int a=0;
int b=0;
int CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    

  if (HC_ACTION==nCode)
    {  if (wParam==WM_KEYDOWN)
        {
             a=b;
             b=0;
            KBDLLHOOKSTRUCT * p = (KBDLLHOOKSTRUCT*)lParam;
            if ((p->vkCode == VK_C) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0))
            { 
               b=1;
                if ((a==1) && (b==1) ) MessageBox(NULL, NULL,NULL,0);
            }
        }
    }
  return CallNextHookEx(hHook, nCode, wParam, lParam);
}


int APIENTRY WinMain(HINSTANCE hInstance,
             HINSTANCE         hPrevInstance,
             LPSTR             lpCmdLine,
             int               nCmdShow)
{
  
  hHook=SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)&KeyboardProc, GetModuleHandle(NULL), 0);
  // цикл сообщений приложения
 
 
  MSG msg = {0};    // структура сообщения
  int iGetOk = 0;   // переменная состояния
  while ((iGetOk = GetMessage(&msg, NULL, 0, 0 )) != 0) // цикл сообщений
  {
    if (iGetOk == -1) return 3;  // если GetMessage вернул ошибку - выход
    TranslateMessage(&msg);    
    DispatchMessage(&msg);
  }
  return 0;  // возвращаем код завершения программы
}


Вроде перехватывает по Ctrl CC, но мне непонятно следующее

1)в документации сказано, что wPAram содержит код виртуальной клавиши.
Сколько раз не жмешь кнопку, значение wParam не меняется (WM_KEYDOWN), а код реально брать вот так надо   

  KBDLLHOOKSTRUCT * p = (KBDLLHOOKSTRUCT*)lParam;
          p->vkCode
Почему wParam не меняется? вроде код написала, но так и не поняла пока

2) Почему  мне написали 
  return CallNextHookEx(hhk, nCode, wParam, lParam); а не return 0?
3) dll теперь надо
PM MAIL   Вверх
jonie
Дата 3.7.2009, 20:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата
2) Почему  мне написали 
  return CallNextHookEx(hhk, nCode, wParam, lParam); а не return 0?

ваш хук может быть не единственным в системе. Почитайте Remarks к SetWindowsHookEx функции в MSDN:
Цитата

Calling the CallNextHookEx function to chain to the next hook procedure is optional, but it is highly recommendedotherwise, other applications that have installed hooks will not receive hook notifications and may behave incorrectly as a result. You should call CallNextHookEx unless you absolutely need to prevent the notification from being seen by other applications. 

Цитата

3) dll теперь надо
а что мешает сделать Длл? Можно сделать COM компонент, ведь наверно Java-е проще общаться с COM ?

Цитата
1)в документации сказано, что wPAram содержит код виртуальной клавиши.

там это несказано:
Цитата

wParam
[in] Specifies the identifier of the keyboard message. This parameter can be one of the following messages: WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP. 

т.е. wParam будет просто одним из сообщением (DWORD-ом, DWORD это типа беззнаковое целое размером в 32бита на x86 системе).

Вам еще нужно не забыть что остановка хуков нужна! Вы обязаны сделать UnhookWindowsHookEx(hHook) после того как вам хук не нужен будет в противном случае возможно вы будете являться причиной деградирования системы...

Скорее всего вас устроит длл (или COM) которая будет содержать функции установки хука, его снятия. При установке создаст глобальный объект синхронизации, например Mutex, и в цикле обработки сообщений сделаете проверку на состояние мьютекса...

В общем-то у меня есть готовая длл-ка, на assembler x86 правда (впрочем не особо суть разница), реализующая не низкоуровневые, а обычные хуки, параметром которой является HWND (хендл окна). Если Java умеет обрабатывать оконные сообщения то мб вам она подойдет...



--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
Iamme
Дата 3.7.2009, 22:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(jonie @ 3.7.2009,  20:17)
Скорее всего вас устроит длл (или COM) которая будет содержать функции установки хука, его снятия. При установке создаст глобальный объект синхронизации, например Mutex, и в цикле обработки сообщений сделаете проверку на состояние мьютекса...


Делаю DLL, так и планирую - 2 метода  - установки (start) и снятия  (stop) хука. 

Код
// dll.cpp: определяет экспортированные функции для приложения DLL.


#include "stdafx.h"
#define VK_C    0x043
HHOOK hHook;
int a=0;
int b=0;
int CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{    

  if (HC_ACTION==nCode)
    {  if (wParam==WM_KEYDOWN)
        {
             a=b;
             b=0;
            KBDLLHOOKSTRUCT * p = (KBDLLHOOKSTRUCT*)lParam;
            if ((p->vkCode == VK_C) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0))
            { 
               b=1;
                if ((a==1) && (b==1) ) MessageBox(NULL, NULL,NULL,0);
            }
        }
    }
  return CallNextHookEx(hHook, nCode, wParam, lParam);
}
__declspec(dllexport)  int start()
{
  
  hHook=SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)&KeyboardProc, GetModuleHandle(NULL), 0);
  // цикл сообщений приложения
 
 
  MSG msg = {0};    // структура сообщения
  int iGetOk = 0;   // переменная состояния
  while ((iGetOk = GetMessage(&msg, NULL, 0, 0 )) != 0) // цикл сообщений
  {
    if (iGetOk == -1) return 3;  // если GetMessage вернул ошибку - выход
    TranslateMessage(&msg);    
    DispatchMessage(&msg);
  }
  return 0;  // возвращаем код завершения программы
}
__declspec(dllexport)  int stop()
{
    UnhookWindowsHookEx(hHook);
    return 0; 
}



Для начала пытаюсь эту dll из с++ вызвать, два метода подряд для теста , вот вызов

Код

// dllmain.cpp: определяет точку входа для приложения DLL.
#include "stdafx.h"

typedef int (__stdcall *MYPROC)(); 
int APIENTRY WinMain(HINSTANCE hInstance,
             HINSTANCE         hPrevInstance,
             LPSTR             lpCmdLine,
             int               nCmdShow)
{
    MYPROC start, stop;
    HINSTANCE dll = LoadLibraryA("simpledll.dll"); 
    if (dll != NULL) 
    { 
        start = (MYPROC) GetProcAddress(dll, "start"); 
        stop = (MYPROC) GetProcAddress(dll, "stop"); 
    } 
    if (start!=NULL) (start)();
    if (stop!=NULL) (stop)();
    
    FreeLibrary(dll);
    return 0;
}


Но адреса  start и stop почему-то нулевые получаются. В чем может быть причина?

PS 
И зачем еще поток Mutex создавать?

PM MAIL   Вверх
jonie
Дата 4.7.2009, 07:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата

Но адреса  start и stop почему-то нулевые получаются. В чем может быть причина?
потому что в dll вашей они незываются не start и stop - работает изменение симоволов в стиле c++.
Включите в длл файд def примерно такого содержимого: 
Код


LIBRARY      "MyMegaHookLibName"

EXPORTS
    start        PRIVATE
    stop            PRIVATE

и уберите __declspec(dllexport)
Также пропишите в опциях компилятора (в нстройках есть) Module Definition File на только что добавленый def файл.

Цитата


И зачем еще поток Mutex создавать?
у вас блокирующий поток start. Вам придется в вызывающем делать поток..... а я лично сделал бы неблокирующий потокобезопасный start и stop...но то дело ваше.



--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
Iamme
Дата 12.7.2009, 09:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(jonie @ 4.7.2009,  07:58)
у вас блокирующий поток start. Вам придется в вызывающем делать поток..... а я лично сделал бы неблокирующий потокобезопасный start и stop...но то дело ваше.

А что значит "неблокирующий потокобезопасный start и stop"? Можно командами?

все это нужно для создания процесса? (в данный момент при использованиии Dll цикл сообщений сразу заканчивается, никакого ожидания нажатий не происходит)
PM MAIL   Вверх
jonie
Дата 12.7.2009, 11:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата
А что значит "неблокирующий потокобезопасный start и stop"? Можно командами?

пример в аттаче. Хотя и его нужно допиливать до полной безопасности.


Присоединённый файл ( Кол-во скачиваний: 32 )
Присоединённый файл  DLLHook.rar 4,87 Kb


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

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


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

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


 




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


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

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