Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 03.01.2012, 21:53
Energy of Fire Energy of Fire вне форума
Прохожий
 
Регистрация: 03.01.2012
Сообщения: 10
Репутация: 10
Печаль глобальный хук сочетаний клавиш для формы

Пожалуйста, помогите советом. Пытаюсь написать компонент (невизуальный), который при нажатии определенной комбинации
клавиш (комбинацию в будущем планируется задаваться в свойсве), выполнил событие пользователя. Как заставить компонент перехватывать нажатия клавиш и реагировать только на назначенные? (перехватывать сообщение с помощью WM_HOTKEY не получилось, также пытался перекрыть WndProc и там отлаливать WM_HOTKEY-безрезультатно...пока остановился на обработке сообщений формы Application.OnMessage, но и тут напоролся на непонятную ошибку... )? Заранее спасибо.
Вложения
Тип файла: rar zZz.rar (180.4 Кбайт, 4 просмотров)
Ответить с цитированием
  #2  
Старый 03.01.2012, 22:56
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,048
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Вот некоторые мои эксперименты:

Код:
private
    procedure WMHotKey(var Message: TMessage); message WM_HOTKEY;

var
 id : DWORD;

procedure TForm1.FormActivate(Sender: TObject);
Const
 VK_D = 68;
begin
 id:= GlobalAddAtom('Hotkey1');
 RegisterHotKey(Form1.Handle, id, MOD_CONTROL, VK_D);
end;

procedure TForm1.WMHotKey(var Message: TMessage);
begin
 Showmessage('Нажаты Ctrl+d');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 UnregisterHotKey(Form1.Handle, id);
end;
Ответить с цитированием
  #3  
Старый 03.01.2012, 23:04
Energy of Fire Energy of Fire вне форума
Прохожий
 
Регистрация: 03.01.2012
Сообщения: 10
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Вот некоторые мои эксперименты:

Код:
private
    procedure WMHotKey(var Message: TMessage); message WM_HOTKEY;

var
 id : DWORD;

procedure TForm1.FormActivate(Sender: TObject);
Const
 VK_D = 68;
begin
 id:= GlobalAddAtom('Hotkey1');
 RegisterHotKey(Form1.Handle, id, MOD_CONTROL, VK_D);
end;

procedure TForm1.WMHotKey(var Message: TMessage);
begin
 Showmessage('Нажаты Ctrl+d');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
 UnregisterHotKey(Form1.Handle, id);
end;
Этот код я юзал много раз...все работало...когда пришлось писать этот компонент, думал что проблем не будет, но WM_HOTKEY в компоненте не хочет ловить глобальный хук комбинации клавиш...я пробывал некоторые другие (выше описанные способы), но к сожалению ничего не вышло...может есть еще какие-нибуть мысли?...
Ответить с цитированием
  #4  
Старый 04.01.2012, 00:25
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,048
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ага, понял в чем проблема.
На самом деле не ловит, потому-что тип компонента, который ты видимо делаешь, не является оконным. Обычно это обходится путем использования окна, на которое "бросается" компонент. В этом случае ты должен сохранить ссылку на существующую WndProc и заменить ее на свою. А в своей проверить на WM_HOTKEY, и если нет, то вызвать сохраненную. Или делать компонент наследником любого оконного (не уверен, что совсем любого, может сообщение посылается только топ-левел окнам), либо просто создавать свое невидимое окно, как делает TTimer.
Ответить с цитированием
  #5  
Старый 04.01.2012, 00:39
Аватар для angvelem
angvelem angvelem вне форума
.
 
Регистрация: 18.05.2011
Адрес: Омск
Сообщения: 3,970
Версия Delphi: 3,5,7,10,12,XE2
Репутация: выкл
По умолчанию

У него оконный компонент и даже была попытка перехватить WndProc, но видно не получилось.
__________________
Je venus de nulle part
55.026263 с.ш., 73.397636 в.д.
Ответить с цитированием
  #6  
Старый 04.01.2012, 00:50
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,048
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Цитата:
Сообщение от angvelem
У него оконный компонент и даже была попытка перехватить WndProc, но видно не получилось.

Ну, тогда только к хирургу, или к кузнецу - руки выпрямлять.
Кстати, на torry.net можно посмотреть компонент HotKeyManager. Как раз то, что товарисч хочет сделать.

ЗЫ. Как я и сказал, TWinControl похоже не годится, нужен TWindow, хотя там вообще намешано - зачем делать оконный компонент, если все-равно перехватываешь сообщение у родительского окна?
В общем - ссылку на пример дал - разбирайтесь.

Последний раз редактировалось lmikle, 04.01.2012 в 00:54.
Ответить с цитированием
  #7  
Старый 04.01.2012, 10:54
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

сам компонент:

Код:
unit HotKey;

interface

uses
  Windows, Messages, Classes;

type
  THotKey = class(TComponent)
  private
    FOnHotKey: TNotifyEvent;
    FWnd: HWND;
    procedure WndMethod(var Message: TMessage);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnHotKey: TNotifyEvent read FOnHotKey write FOnHotKey;
  end;

implementation

{ THotKey }

constructor THotKey.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FWnd:=AllocateHWnd(WndMethod);
  RegisterHotKey(FWnd, 1, MOD_CONTROL, Ord('G'));
end;

destructor THotKey.Destroy;
begin
  UnregisterHotKey(FWnd, 1);
  DeallocateHWnd(FWnd);
  inherited Destroy;
end;

procedure THotKey.WndMethod(var Message: TMessage);
begin
  if Message.Msg=WM_HOTKEY then
  begin
    if Assigned(FOnHotKey) then FOnHotKey(Self);
  end else
    Message.Result:=DefWindowProc(FWnd, Message.Msg,
      Message.WParam, Message.LParam);
end;

end.

использование:

Код:
uses
  HotKey,

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure HotKeyClick(Sender: TObject);

procedure TForm1.FormCreate(Sender: TObject);
begin
  with THotKey.Create(Self) do
    OnHotKey:=HotKeyClick;
end;

procedure TForm1.HotKeyClick(Sender: TObject);
begin
  ShowMessage('HotKeyClick');
end;
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #8  
Старый 04.01.2012, 12:34
Energy of Fire Energy of Fire вне форума
Прохожий
 
Регистрация: 03.01.2012
Сообщения: 10
Репутация: 10
По умолчанию

Этот вариант, несомненно, хорош, но как он будет выполнять событие, для не динамически созданного компонента?...ведь для динамического используется THotKey.Create(Self).OnHotKey:=HotKeyClick.И еще один вопрос...можно ли без переприсваивания сделать рабочим событие OnHotKey (как для динам. созданного компонета, так и для обыкновенного, и если можно, то как...) ?
Ответить с цитированием
  #9  
Старый 04.01.2012, 15:17
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Цитата:
Сообщение от Energy of Fire
но как он будет выполнять событие, для не динамически созданного компонента?
точно также. свойство OnHotKey published. т.е. через инспектор объектов можно будет обработчик задать. вспомни как для динамической кнопки обработчик присваивается...
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
Этот пользователь сказал Спасибо NumLock за это полезное сообщение:
Energy of Fire (04.01.2012)
  #10  
Старый 04.01.2012, 15:26
Energy of Fire Energy of Fire вне форума
Прохожий
 
Регистрация: 03.01.2012
Сообщения: 10
Репутация: 10
По умолчанию

На этот вопрос:... можно ли, без переприсваивания сделать рабочим событие OnHotKey (как для динам. созданного компонета, так и для обыкновенного, и если можно, то как...?
Если кому-нибудь будет интересно, то чтобы решить эту проблему, я использовал вместо procedure WndMethod(var Message: TMessage), вот это procedure HookProc(var Msg: TMessage); virtual и обязательно это занесите в protected, т.к. если тестить это все отладчике, то он не заходит в процеруду, если она лежит в public или private (это я говарю, так как сам продалбался несколько часов...как исправилась проблема с нерабочим событием я пока и сам толком не понял)

Всем спасибо за помощь в решении проблемы!

Последний раз редактировалось Energy of Fire, 04.01.2012 в 15:47.
Ответить с цитированием
  #11  
Старый 04.01.2012, 15:34
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

Цитата:
Сообщение от Energy of Fire
хотелось бы просто сделать пару кликов на событие в инспекторе, и написать туда какой-нить код...?
на самом деле будет даже 1 клик на OnHotKey в инспекторе и Delphi сама создаст код обработчика, как она это делает для кнопок.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #12  
Старый 04.01.2012, 20:12
Energy of Fire Energy of Fire вне форума
Прохожий
 
Регистрация: 03.01.2012
Сообщения: 10
Репутация: 10
По умолчанию

...кто нибудь может подсказать, как работает DefWindowProc, если HookProc ловит WM_HOTKEY...и зачем вообще эта процедура...в инете читал, что DefWindowProc нужен в том случае, если сообщение не поймали...и нужно пустить дальше его в windows.Но если я поставлю комбинацию клавиш ctrl+v и попытаюсь вставить что-нибудь в блокнот, то хоткей перехватит это нажатие,выполнит событие, и дальше не передаст хотя я поставил DefWindowProс для передачи сообщения дальше...как сделать чтобы сообщение дошло и до приложения и передала дальше в винду и где-нибудь в текстовом блокноте сработала вставка.
Код:
procedure THotKey.HookProc(var Msg: TMessage);
begin
  if (Msg.Msg=WM_HOTKEY)  then
  begin
    if Assigned(FOnHotKey) then FOnHotKey(Self);
  end;
  Msg.Result:=DefWindowProс(FWnd,Msg.Msg,Msg.WParam, Msg.LParam);
end;

lmikle: Пользуемся тегами!!!

Последний раз редактировалось lmikle, 04.01.2012 в 22:15.
Ответить с цитированием
  #13  
Старый 04.01.2012, 21:43
Аватар для angvelem
angvelem angvelem вне форума
.
 
Регистрация: 18.05.2011
Адрес: Омск
Сообщения: 3,970
Версия Delphi: 3,5,7,10,12,XE2
Репутация: выкл
По умолчанию

В том варианте как у тебя написано, после обработки Msg.Msg=WM_HOTKEY управление передаётся на обработчик по-умолчанию (DefWindowProс), но если сделать так:
Код:
procedure THotKey.HookProc(var Msg: TMessage);
begin
  if (Msg.Msg = WM_HOTKEY) then
  begin
    if Assigned(FOnHotKey) then FOnHotKey(Self);
    Exit;
  end;
  Msg.Result := DefWindowProс(FWnd,Msg.Msg,Msg.WParam, Msg.LParam);
end;
то обработка прервётся для данного сообщения и в "Блокнот" уже ничего не вставишь. Можешь принудительно послать на дальнейшую обработку:
Код:
procedure THotKey.HookProc(var Msg: TMessage);
begin
  if (Msg.Msg = WM_HOTKEY) then
  begin
    if Assigned(FOnHotKey) then FOnHotKey(Self);
    Msg.Result := DefWindowProс(FWnd,Msg.Msg,Msg.WParam, Msg.LParam);
  end;
  Msg.Result := DefWindowProс(FWnd,Msg.Msg,Msg.WParam, Msg.LParam);
end;
__________________
Je venus de nulle part
55.026263 с.ш., 73.397636 в.д.
Ответить с цитированием
  #14  
Старый 04.01.2012, 22:40
Energy of Fire Energy of Fire вне форума
Прохожий
 
Регистрация: 03.01.2012
Сообщения: 10
Репутация: 10
По умолчанию

в первом случае вместо ехит у меня было раньше елс и там стояла процедура DefWindowProс, во втором случае твой код практически не отличается от моего, но ты непонятно для чего ставишь опять DefWindowProс(я от безысходности попробывал 2 твои варианта ни один не работает)...могу скинуть то, что имею сейчас…покавыряемся вместе…
Вложения
Тип файла: rar HKey.rar (227.8 Кбайт, 1 просмотров)

Последний раз редактировалось Energy of Fire, 04.01.2012 в 23:10.
Ответить с цитированием
  #15  
Старый 05.01.2012, 11:24
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

ну естественно, что если поставить хоткей на Ctrl+V, то в Блокнот ничего не вставится - ему просто не будет приходить WM_PASTE. и DefWindowProc тут абсолютно ни при чем. чтобы Блокноту приходило WM_PASTE нужно в обработчике OnHotKey написать код, к примеру такой:

Код:
var
  AWindow: THandle;
  AThreadId: Cardinal;
  AProcessId: Cardinal;
begin
  Windows.Beep(1000, 100); //////////
  AWindow:=GetForegroundWindow;
  AThreadId:=GetCurrentThreadId;
  AProcessId:=GetWindowThreadProcessId(AWindow, nil);
  AttachThreadInput(AThreadId, AProcessId, True);
  SendMessage(GetFocus, WM_PASTE, 0, 0);
  AttachThreadInput(AThreadId, AProcessId, False);
end;

теперь активному окну (the window that has the keyboard focus) будет посылаться сообщение WM_PASTE.
__________________
Пишу программы за еду.
__________________

Последний раз редактировалось NumLock, 05.01.2012 в 11:27.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 18:10.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter