Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

отловить комбинацию WIN+E

330
02 декабря 2012 года
kastron
215 / / 17.09.2006
помогите пожалуйста разобраться нужно отловить на своей форме, что нажата комбинация win+e, 91 - виртуальный код клавиши левой WIN, 69 - виртуальный код клавиши E
onKeyDown формы стоит
Код:
if GetAsyncKeyState(69) <> 0) then
begin
  showmessage('нажата E');
end;

if GetAsyncKeyState(91) <> 0) then
begin
  showmessage('нажата левая WIN');
end;

//все нормально, обрабатывается

//а на комбинацию не реагирует

if (GetAsyncKeyState(69) <> 0) and (GetAsyncKeyState(91) <> 0) then
 begin
  showmessage('WIN+E');
 end;
465
02 декабря 2012 года
QWERYTY
595 / / 25.03.2012
Да, действительно странно. Ваш код не работает, хотя судя из описания функций должен.

Я даже скажу больше, каким то чудом вот такой код тоже не работает:
Код:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
KeyBuff: TKeyboardState;
begin
     // if key = 69 then
     // begin
      FillChar(KeyBuff, SizeOf(KeyBuff), 0);
      GetKeyboardState(KeyBuff);
      if (KeyBuff[90] = 1) and (KeyBuff[68] = 1) then
      begin

         ShowMessage('O ya, baby');

         end;
    //  end;


end;
Може быть это связанно с тем что в момент нажатия 'е' форма тут же теряет фокус и не успевает сработать onKeyDown. Точно не знаю, это лиш предположение.

По ходу тут нужен какой то более суровый перехват
465
03 декабря 2012 года
QWERYTY
595 / / 25.03.2012
Заинтересовался я вашей задачей, очень мне показалась полезной на будущее.
Не знаю как у вас на данный момент, но у меня не получилось добиться перехвата именно Win + E. Получилось E + Win .

Поэтому было принято решение поставить низкоуровневый хук клавиатуры(функция-фильтр):
Код:
function KeyboardProc(Code: INTEGER; WParam: INTEGER; LParam: INTEGER): INTEGER; stdcall;
begin
   if Code < 0 then
   begin
      Result := CallNextHookEx(Hook, Code, WParam, LParam);
      Exit;
      end;


   if WParam = WM_KEYUP then
   begin
     if (GetAsyncKeyState(69) <> 0) and (GetAsyncKeyState(91) <> 0) then
     begin
           // Обрабатываем нажатие тут

         ShowMessage('O ya, baby');


       end;
    end;


    Result := CallNextHookEx(Hook, Code, WParam, LParam);
end;
и при создании формы ставим:
 
Код:
Hook := SetWindowsHookEx(WH_KEYBOARD_LL, @KeyboardProc, Hinstance, 0);
Обратите внимание. Хук реагирует на отжатие клавиш, а не на нажатие как может показаться логичным.
Дело в том что хук срабатывает до изменения состояния клавиатуры. И если считывать по событию WM_KEYDOWN то окажется что клавиши ещё не нажаты.
Это как в фильме терминатор. Он ещё не был создан, но уже убивал джона конора :-)


В общем этому хуку по барабану в фокусе окно или нет. Если нажали Win + E и открылся проводник то и вы получите событие.
Здесь есть одна проблемка. В виду крайней простоты код реагирует и на E + Win .
Если задача не проворонить открытие проводника то этого достаточно.
465
03 декабря 2012 года
QWERYTY
595 / / 25.03.2012
И ещё. Вы будете получать одно событие при каждом отжатии последней из клавиш. При этом могут удерживать это сочетание клавиш и откроется 100500 проводников.

Не забывайте снимать хук, когда закрывается программа или он больше не нужен.
465
03 декабря 2012 года
QWERYTY
595 / / 25.03.2012
Перевый мой ответ не достаточно я почитал про GetKeyboardState. Но когда я почитал повнимательней то вообще чуть не завис на всегда. Там погнали про какую то хрень типа четное количество раз были нажаты кнопки или нет.
Какая может быть разница программисту четное или нет. Если действительно понадобилось бери да считай.
В общем мне это показалось натуральной дурью.
3.7K
03 декабря 2012 года
0nni
326 / / 24.06.2008
Можно RegisterHotkey подойдет для вашей задачи?
330
03 декабря 2012 года
kastron
215 / / 17.09.2006
2QWERYTY
Спасибо за информацию. Один момент
в коде
 
Код:
Hook := SetWindowsHookEx(WH_KEYBOARD_LL, @KeyboardProc, Hinstance, 0);
пишет Undeclared identifier WH_KEYBOARD_LL, пробовал без _LL запускается, но тогда хук не работает.
И еще хотелось бы прояснить мне нужно если активна моя форма и нажато win+e перехватить его и заблокировать, возможно ли это сделать по человечески?
а не например в хуке искать по заголовку окна "Мой компьютер" и убивать его?
Такая же задача актуальна насчет WIN+R
Спасибо
465
03 декабря 2012 года
QWERYTY
595 / / 25.03.2012
Вставьте вот это, в любое место(я это делаю перед объявлением глобальных переменных):
 
Код:
const
   WH_KEYBOARD_LL = 13;
По ходу у вас эта константа не объявлена.


Без _LL ставится другой хук. Там назначение WParam и LParam другое. Правильно что не работал.
Хотел спросить запрешать планируете или только отлов, зря не стал. Ладно подумаем.

Какая студия? Вы вообще под виндовс пишете, а то "Delphi & Kylix" очень информативно?

Вы бы сразу поставили задачу нормально. Я правильно понимаю? Вы не хотите чтоб нажатие WIN + E попало в процесс explorer. Если так то хук по любому, вопрос какой. По логике должен быть хук который вызывается после смены состояния клавиатуры, но до отправки сообщения об этом всем процессам. Вот в этот момент нужно получить состояние интересующих кнопок и если оно не устраивает сменить


Есть конечно другие варианты, по типу внедрения в explorer и предотвращение реакции от туда, но это тяжкие методы
465
04 декабря 2012 года
QWERYTY
595 / / 25.03.2012
Так, всётаки хук был выбран правильно. Хуком WH_KEYBOARD не получается отменить нажатие WIN, хотя я получаю событие но ни Exit ни передача result := 1 не влияют на открытие окна.

Попробуйте вот такой код(функция-фильтр низкоуровневого хука):

Код:
function KeyboardProc(Code: INTEGER; WParam: INTEGER; LParam: INTEGER): INTEGER; stdcall;
var
KeyboardInfo: PLLKEYBOARDINFO;
begin
   if Code < 0 then
   begin
      Result := CallNextHookEx(Hook, Code, WParam, LParam);
      exit;
      end;

   if Code = HC_ACTION then
   begin
      case WParam of
      WM_SYSKEYDOWN, WM_KEYDOWN:
      begin
         KeyboardInfo := PLLKEYBOARDINFO(LParam);
         if (KeyboardInfo.vkCode = 69) and (GetAsyncKeyState(91) <> 0) then
         begin
            Result := 1;
            exit;
            end;
         end;
      end;

   end;

   Result := CallNextHookEx(Hook, Code, WParam, LParam);
end;
Там будет работа с самопальным типом, вот его описание:

 
Код:
type
  PLLKEYBOARDINFO = ^TLLKEYBOARDINFO;
  TLLKEYBOARDINFO = packed record
                    vkCode: CARDINAL;
                    scanCode: CARDINAL;
                    flags: CARDINAL;
                    time: CARDINAL;
                    dwExtraInfo: CARDINAL;
                    end;
У меня с таким кодом нивкакую не открывается проводник. По отдельности кнопки работают.
В общем тут мы не допускаем их нажатия, поэтому их удержание в расчёте на появление проводника тоже не проканывает
465
05 декабря 2012 года
QWERYTY
595 / / 25.03.2012
Сразу по простому не пошло. Понятно было что вся инфа о состоянии клавиатуры перед срабатыванием нажатия передаётся в этот хук клавы низкого уровня через WParam и LParam. Но долго не мог найти инфу как интерпретировать LParam в случае WH_KEYBOARD_LL

А код в вопросе не решает таких задач. На момент когда ваша ппрограмма получает сообщение о нажатии этих клавиш предотвращать это событие уже поздно.
330
05 декабря 2012 года
kastron
215 / / 17.09.2006
2QWERYTY
Спасибо! Все работает. Проверял на среде Delphi7
330
04 января 2013 года
kastron
215 / / 17.09.2006
2QWERYTY
Скажи пожалуйста, а можно сделать так, чтобы при том коде, что указал ты выше не появлялось меню ПУСК при нажатии комбинации WIN+E? Спасибо.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог