Форум программистов, компьютерный форум, киберфорум
Наши страницы
Lazarus
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
Andrew Puchinin
2 / 3 / 1
Регистрация: 25.04.2016
Сообщений: 105
#1

Считать нажатый символ в фоновом режиме

14.06.2016, 17:40. Просмотров 676. Ответов 18
Метки нет (Все метки)

Здравствуйте.
Читал что-то про ловушки в Delphi, мало, что понял. Можете написать код программы с помощью ловушек, которая, скажем, повторяет нажатый символ. То есть я запускаю программу, оставляю её работать где-то позади, сам открываю блокнот, нажимаю 'а', и в блокноте возникает две буквы а. Нажимаю б - две буквы б.
И объясните, пожалуйста, заодно, как вообще с этими ловушками работать.
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.06.2016, 17:40
Ответы с готовыми решениями:

Программа в фоновом режиме
Программисты, прошу помощи!! Дали вот такое задание: Создайте приложение,...

СистемнаяИнформация в фоновом режиме
добрый день, друзья. Обнаружено странное поведение. есть код ...

Работа в фоновом режиме
Сразу извиняюсь за название темы и раздел. Я не знал, где эту тему создать и...

Съёмка в фоновом режиме
Как получить картинку с камеры в фоновом режиме (без Surface)? Неважно, на...

Уведомления в фоновом режиме
Пишу органайзер, в котором у меня есть раздел с Событиями (дата и описание)....

18
Joey
Форумчанин
831 / 552 / 219
Регистрация: 05.05.2015
Сообщений: 3,199
Записей в блоге: 1
15.06.2016, 13:23 #2
Andrew Puchinin, есть такая функция WinAPI RegisterHotKey, она регистрирует любую клавишу в системе так, чтобы при нажатии этой клавиши твоя программа была уведомлена. Все, что я могу предложить по твоей задаче - это зарегестрировать таким образом все клавиши на клавиатуре

Добавлено через 2 минуты
И при нажатии той или иной клавиши посылать активному окну (GetForeGroundWindow https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx - получить активное окно, SendMessage http://www.vsokovikov.narod.ru/New_M...endmessage.htm - послать сообщение этому окну, в твоем случае - WM_KeyDown - https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx)
1
Andrew Puchinin
2 / 3 / 1
Регистрация: 25.04.2016
Сообщений: 105
17.06.2016, 13:45  [ТС] #3
Joey, правильно ли я понял, что RegisterHotKey определяет только комбинацию клавиш, которая начинается с вспомогательных клавиш, вроде Alt, Ctrl и т.д. ?

Добавлено через 4 минуты
третий параметр fsModifiers принимает значения, указывая на нажатие этих клавиш. Может можно приравнять его nill...
0
Joey
Форумчанин
831 / 552 / 219
Регистрация: 05.05.2015
Сообщений: 3,199
Записей в блоге: 1
17.06.2016, 14:03 #4
Andrew Puchinin, просто не посылаете ни одного модифаера, передаете []
0
Andrew Puchinin
2 / 3 / 1
Регистрация: 25.04.2016
Сообщений: 105
17.06.2016, 15:31  [ТС] #5
Спасибо, и еще вопрос: второй параметр RegisterHotKey - идентификатор - указано, что, чтобы избежать конфликта с уже существующими идентификаторами, нужно использовать функцию GlobalAddAtom. Что мне нужно передать туда в параметрах, чтобы получить правильный уникальный id?

Добавлено через 15 минут
и кстати, попробовал, на [] ругается: Incompatible type for arg no. 3: Got "Array Of Const", expected "LongWord"

Добавлено через 9 минут
Можно я для простоты задачи попрошу написать строку обработки одного символа? У меня выходит так:

Delphi
1
2
3
4
5
6
7
8
9
10
var
  Wind: THandle;
  a_pressed: boolean;
 
begin
  Wind:=GetForeGroundWindow();
  a_pressed:=RegisterHotKey(Wind,GlobalAddAtom(<smth>),<smth>,ord('a'));
  if (a_pressed=true) then
    ...
end.
И, собственно, вопрос, что должно быть на месте двух пропусков. Во втором случае, на сколько я понимаю, надо как-то создать пустую переменную типа LongWord.
0
volvo
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
25966 / 17410 / 6906
Регистрация: 22.10.2011
Сообщений: 30,649
Записей в блоге: 6
17.06.2016, 18:37 #6
Цитата Сообщение от Andrew Puchinin Посмотреть сообщение
на [] ругается
Разумеется. Если нет модификаторов - надо передавать не пустое множество, и не пустой константный массив, а просто 0.
Цитата Сообщение от Andrew Puchinin Посмотреть сообщение
что должно быть на месте двух пропусков
На месте второго - 0, как уже написано выше. А на месте первого - название атома (строка), но нужно запомнить, что вернет GlobalAddAtom, чтобы потом нормально удалить горячую клавишу через UnRegisterHotKey. И не забыть удалить сам атом через GlobalDeleteAtom...
0
Andrew Puchinin
2 / 3 / 1
Регистрация: 25.04.2016
Сообщений: 105
17.06.2016, 19:36  [ТС] #7
Я чего-то не так делаю... Пытаюсь продебажить, a_pressed всегда равно false:

Delphi
1
2
id:=GlobalAddAtom('a');
a_pressed:=RegisterHotKey(Wind,id,0,ord('a'));
А GlobalDeleteAtom ругается на то, что передаваемый параметр не типа Word. Как GlobalAddAtom и GlobalDeleteAtom могут принимать параметры разных типов?..
0
volvo
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
25966 / 17410 / 6906
Регистрация: 22.10.2011
Сообщений: 30,649
Записей в блоге: 6
17.06.2016, 22:57 #8
Цитата Сообщение от Andrew Puchinin Посмотреть сообщение
a_pressed всегда равно false:
Чтобы найти причину:
If the function fails, the return value is zero. To get extended error information, call GetLastError.
А вообще:
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// класс формы:
  TForm1 = class(TForm)
    // ...
  private
  public
    id : ATOM; // Вот с такими описаниями
    a_pressed : BOOL;
  end; 
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  id:=GlobalAddAtom('MyAtom');
  a_pressed:=RegisterHotKey(Handle,id,0,ord('a')); // все нормально создается, a_pressed = true
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  UnRegisterHotKey(Handle, id);
  GlobalDeleteAtom(id);
end;
0
Andrew Puchinin
2 / 3 / 1
Регистрация: 25.04.2016
Сообщений: 105
18.06.2016, 00:36  [ТС] #9
Создал. Запустилось. Но, простите пожалуйста... почему a_pressed теперь всегда равно true? Можно еще раз насчет изначальной задачи - нужно отловить нажатие на символ вне программы, т.е. a_pressed должно быть равно true только в том случае, когда нажался символ где-либо в системе. volvo, В Вашей программе a_pressed действительно всегда равно true, или это я опять чего-то не понимаю?.. Если всегда, то еще раз вопрос - как этот код изменить так, чтобы отлавливать нажатие на символ?
P.s.: я поставил на форму таймер, чтобы программа не завершалась сразу после первого ввода.
0
volvo
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
25966 / 17410 / 6906
Регистрация: 22.10.2011
Сообщений: 30,649
Записей в блоге: 6
18.06.2016, 00:42 #10
Цитата Сообщение от Andrew Puchinin Посмотреть сообщение
a_pressed должно быть равно true только в том случае, когда нажался символ где-либо в системе
a_pressed - это признак успешности/неуспешности установки горячей клавиши. А чтобы сами нажатия таких клавиш ловить - нужно ловить сообщение WM_HOTKEY, и там отлавливать только те, у которых WPARAM = id. Это и будут нажатые "а" без модификатора. И вот тогда уже делать с ними, что нужно, отсылать еще одно нажатие в активное окно, или еще чего.
0
Andrew Puchinin
2 / 3 / 1
Регистрация: 25.04.2016
Сообщений: 105
18.06.2016, 13:59  [ТС] #11
У меня заработали вспомогательные клавиши и цифры. Работать не хотят почему-то только буквы. Вот код:

Delphi
1
2
3
4
5
6
7
procedure TForm1.FormCreate(Sender: TObject);
begin
  id1:=GlobalAddAtom('SPACE');
  RegisterHotKey(Handle,id1,0,VK_SPACE);
  id2:=GlobalAddAtom('A');
  RegisterHotKey(Handle,id2,0,ord('A'));
end;
Delphi
1
2
3
4
5
6
7
procedure TForm1.WMHotKey(var Mes: TMessage);
begin
  if (Mes.WParam=id1) then
    Edit1.Text:=Edit1.Text+' 1';
  if (Mes.WParam=id2) then
    Edit2.Text:=Edit2.Text+' 2';
end;
Delphi
1
2
3
4
5
6
7
Procedure TForm1.FormDestroy(Sender: TObject);
begin
  UnRegisterHotKey(Handle,id1);
  UnRegisterHotKey(Handle,id2);
  GlobalDeleteAtom(id1);
  GlobalDeleteAtom(id2);
end;
В случае SPACE все замечательно работает, в случае с A - нет.

Добавлено через 17 минут
Только, если вводить пробел в другой программе, он в ней не печатается и только выводит единички на форму
0
volvo
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
25966 / 17410 / 6906
Регистрация: 22.10.2011
Сообщений: 30,649
Записей в блоге: 6
18.06.2016, 16:25 #12
Лучший ответ Сообщение было отмечено Andrew Puchinin как решение

Решение

Может тебе все-таки хуками воспользоваться?
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
uses ..., JwaWinUser;
 
function LLKeyProc(nCode: integer; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;
var
  vk: DWORD;
begin
  if nCode = HC_ACTION then
  begin
    vk := LPKBDLLHOOKSTRUCT(lp)^.vkCode;
    if wParam = WM_KEYDOWN then
      case vk of
        VK_A:
          Form1.Edit2.Text := Form1.Edit2.Text + ' 2';
        VK_SPACE:
          Form1.Edit1.Text := Form1.Edit1.Text + ' 1';
      end;
  end;
  Result := CallNextHookEx(0, nCode, wp, lp);
end;
 
var
  hook: HHOOK;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  hook := SetWindowsHookEx(WH_KEYBOARD_LL, @LLKeyProc, GetModuleHandle(nil), 0);
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  UnhookWindowsHookEx(hook);
end;
прекрасно ловит нажатия...
2
Andrew Puchinin
2 / 3 / 1
Регистрация: 25.04.2016
Сообщений: 105
18.06.2016, 21:43  [ТС] #13
Да, спасибо, работает. Только не реагирует на строчные символы, но я его в этом уже победил. Правда, думаю, немного через пятую точку:

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
var
  hook, hook2: HHOOK;
  Caps: boolean;
 
function CapsLLKeyProc(nCode: integer; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;
var
  vk: DWORD;
  Window: THandle;
begin
  Caps:=true;
  Window:=GetForeGroundWindow();
  if nCode = HC_ACTION then
    begin
      vk := LPKBDLLHOOKSTRUCT(lp)^.vkCode;
      if (wp = WM_KEYDOWN) then
        begin
          case vk of
            ord('A'):
              Form1.Edit2.Text := Form1.Edit2.Text + ' A2';
          end;
        end;
    end;
  Result := CallNextHookEx(0, nCode, wp, lp);
  UnhookWindowsHookEx(hook2);
end;
 
function LLKeyProc(nCode: integer; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;
var
  vk: DWORD;
  Window: THandle;
begin
  Window:=GetForeGroundWindow();
  if nCode = HC_ACTION then
  begin
    vk := LPKBDLLHOOKSTRUCT(lp)^.vkCode;
    if (wp = WM_KEYDOWN) then
      begin
        case vk of
          ord('A'):
            if (Caps=false) then
              Form1.Edit2.Text := Form1.Edit2.Text + ' a2';
          160:
            begin
              hook2:=SetWindowsHookEx(WH_KEYBOARD_LL,@CapsLLKeyProc,
                                      GetModuleHandle(nil), 0);
            end;
        end;
      end;
  end;
  if (Caps=true) then
    Caps:=false;
  Result := CallNextHookEx(0, nCode, wp, lp);
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  Caps:=false;
  hook := SetWindowsHookEx(WH_KEYBOARD_LL, @LLKeyProc,
                           GetModuleHandle(nil), 0);
end;
 
Procedure TForm1.FormDestroy(Sender: TObject);
begin
   UnhookWindowsHookEx(hook);
end;
И кстати, кажется не

Delphi
1
if wParam = WM_KEYDOWN then
а

Delphi
1
if wp = WM_KEYDOWN then
volvo, можно еще один глупый вопрос? Если коротко, как послать сообщение открытому окну о том, что нажата клавиша?

Цитата Сообщение от Joey Посмотреть сообщение
Andrew Puchinin, есть такая функция WinAPI RegisterHotKey, она регистрирует любую клавишу в системе так, чтобы при нажатии этой клавиши твоя программа была уведомлена. Все, что я могу предложить по твоей задаче - это зарегестрировать таким образом все клавиши на клавиатуре
Добавлено через 2 минуты
И при нажатии той или иной клавиши посылать активному окну (GetForeGroundWindow https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx - получить активное окно, SendMessage http://www.vsokovikov.narod.ru/New_M...endmessage.htm - послать сообщение этому окну, в твоем случае - WM_KeyDown - https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx)
Можно пояснить для особо одаренных?
1
volvo
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
25966 / 17410 / 6906
Регистрация: 22.10.2011
Сообщений: 30,649
Записей в блоге: 6
18.06.2016, 21:55 #14
Цитата Сообщение от Andrew Puchinin Посмотреть сообщение
как послать сообщение открытому окну о том, что нажата клавиша?
Зачем? Открытое окно готово получить это сообщение? При использовании хука ничего никому посылать не нужно, окно и так получит нажатие клавиши. Ну, а если нужно выслать какое-то сообщение, которое это окно умеет обрабатывать - то выше уже было написано: получить хендл активного окна через GetForegroundWindow и выслать ему сообщение через SendMessage, в чем проблема?
0
Joey
Форумчанин
831 / 552 / 219
Регистрация: 05.05.2015
Сообщений: 3,199
Записей в блоге: 1
18.06.2016, 22:01 #15
Andrew Puchinin, Функция SendMessage.
А в одном комментарии на форуме этого не объяснишь, WinAPI - очень сложная штука (по крайней мере, для новичка точно)
0
Andrew Puchinin
2 / 3 / 1
Регистрация: 25.04.2016
Сообщений: 105
18.06.2016, 23:07  [ТС] #16
Цитата Сообщение от volvo Посмотреть сообщение
Зачем? Открытое окно готово получить это сообщение? При использовании хука ничего никому посылать не нужно, окно и так получит нажатие клавиши.
Я возвращаюсь к задаче вывода символа в текущее окно:

Цитата Сообщение от Andrew Puchinin Посмотреть сообщение
Можете написать код программы с помощью ловушек, которая, скажем, повторяет нажатый символ. То есть я запускаю программу, оставляю её работать где-то позади, сам открываю блокнот, нажимаю 'а', и в блокноте возникает две буквы а. Нажимаю б - две буквы б.
Цитата Сообщение от volvo Посмотреть сообщение
Ну, а если нужно выслать какое-то сообщение, которое это окно умеет обрабатывать - то выше уже было написано: получить хендл активного окна через GetForegroundWindow и выслать ему сообщение через SendMessage, в чем проблема?
Проблема только в том, что я плохо понимаю, что передавать в параметрах конструкции

Delphi
1
function SendMessage(Wnd: HWnd; Msg, wParam: Word; lParam: Longint): Longint;
Если с Hwnd более менее понятно, что надо определить окно уже использованным ранее GetForegroundWindow, и, если с Msg кажется ясно, что надо передать константу Wm_KeyDown, то с остальными я затрудняюсь. Пытался передать wParam и lParam из текущей функции, но это было стрельбой по воробьям...

Цитата Сообщение от Joey Посмотреть сообщение
А в одном комментарии на форуме этого не объяснишь, WinAPI - очень сложная штука (по крайней мере, для новичка точно)
Joey, самый прикол в том, что официально я обучался WinApi около года... Только на с++ и уже несколько лет назад. Правда, до меня только сейчас медленно дошло, что оно одинаково как для си, так и для паскаля, и вообще любых языков... В любом случае, я всем ответчикам очень благодарен. Буду еще больше благодарен, если подскажите, как навести порядок в голове и что для этого поискать и почитать (и вопрос все-таки остается открытым).
0
Joey
Форумчанин
831 / 552 / 219
Регистрация: 05.05.2015
Сообщений: 3,199
Записей в блоге: 1
18.06.2016, 23:22 #17
Andrew Puchinin, на форуме есть некоторое количество тем по этим конкретно функциям (как минимум, несколько лично моих тем). Идете в раздел Лазарус, нажимаете искать в этом разделе и вводите, например, SendMessage: http://www.cyberforum.ru/search.php?searchid=11380503

Добавлено через 11 минут
Как вызвать из проги notepad и передать ему текст?
Вывод сообщения из SendMessage
Не получается принять сообщение (SendMessage)
Текстовый редактор в Lazarus
Можете посмотреть примеры, как их используют другие юзеры
0
Andrew Puchinin
2 / 3 / 1
Регистрация: 25.04.2016
Сообщений: 105
19.06.2016, 13:40  [ТС] #18
Все, заработало, заюзал Keybd_event. Правда опять сделал, как можно запутанней, но вышло. Спасибо всем, уря, тему наконец можно закрыть)
0
ПраПрапорщик
10 / 7 / 3
Регистрация: 14.07.2015
Сообщений: 254
19.06.2016, 15:35 #19
Andrew Puchinin, Выбери лучший ответ-это и будет закрытие темы)
0
19.06.2016, 15:35
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.06.2016, 15:35

Sleep() в фоновом режиме
Мне надо, чтобы пока функция sleep() выполняется, я мог еще что-то делать, но...

Работа в фоновом режиме
Приветствую всех. Вопрос следующий. Как сделать так, чтобы работа выполняла...

Работа в Фоновом режиме!
Хочу написать таймер для отключения компьютера(после включения сворачивается в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru