|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
глобальный хук сочетаний клавиш для формы
Пожалуйста, помогите советом. Пытаюсь написать компонент (невизуальный), который при нажатии определенной комбинации
клавиш (комбинацию в будущем планируется задаваться в свойсве), выполнил событие пользователя. Как заставить компонент перехватывать нажатия клавиш и реагировать только на назначенные? (перехватывать сообщение с помощью WM_HOTKEY не получилось, также пытался перекрыть WndProc и там отлаливать WM_HOTKEY-безрезультатно...пока остановился на обработке сообщений формы Application.OnMessage, но и тут напоролся на непонятную ошибку... )? Заранее спасибо. |
#2
|
|||
|
|||
Вот некоторые мои эксперименты:
Код:
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
|
|||
|
|||
Цитата:
|
#4
|
|||
|
|||
Ага, понял в чем проблема.
На самом деле не ловит, потому-что тип компонента, который ты видимо делаешь, не является оконным. Обычно это обходится путем использования окна, на которое "бросается" компонент. В этом случае ты должен сохранить ссылку на существующую WndProc и заменить ее на свою. А в своей проверить на WM_HOTKEY, и если нет, то вызвать сохраненную. Или делать компонент наследником любого оконного (не уверен, что совсем любого, может сообщение посылается только топ-левел окнам), либо просто создавать свое невидимое окно, как делает TTimer. |
#5
|
||||
|
||||
У него оконный компонент и даже была попытка перехватить WndProc, но видно не получилось.
Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. |
#6
|
|||
|
|||
Цитата:
Ну, тогда только к хирургу, или к кузнецу - руки выпрямлять. Кстати, на torry.net можно посмотреть компонент HotKeyManager. Как раз то, что товарисч хочет сделать. ЗЫ. Как я и сказал, TWinControl похоже не годится, нужен TWindow, хотя там вообще намешано - зачем делать оконный компонент, если все-равно перехватываешь сообщение у родительского окна? В общем - ссылку на пример дал - разбирайтесь. Последний раз редактировалось lmikle, 04.01.2012 в 00:54. |
#7
|
||||
|
||||
сам компонент:
Код:
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
|
|||
|
|||
Этот вариант, несомненно, хорош, но как он будет выполнять событие, для не динамически созданного компонента?...ведь для динамического используется THotKey.Create(Self).OnHotKey:=HotKeyClick.И еще один вопрос...можно ли без переприсваивания сделать рабочим событие OnHotKey (как для динам. созданного компонета, так и для обыкновенного, и если можно, то как...) ?
|
#9
|
||||
|
||||
Цитата:
Пишу программы за еду. __________________ |
Этот пользователь сказал Спасибо NumLock за это полезное сообщение: | ||
Energy of Fire (04.01.2012)
|
#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
|
||||
|
||||
Цитата:
Пишу программы за еду. __________________ |
#12
|
|||
|
|||
...кто нибудь может подсказать, как работает 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
|
||||
|
||||
В том варианте как у тебя написано, после обработки 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
|
|||
|
|||
в первом случае вместо ехит у меня было раньше елс и там стояла процедура DefWindowProс, во втором случае твой код практически не отличается от моего, но ты непонятно для чего ставишь опять DefWindowProс(я от безысходности попробывал 2 твои варианта ни один не работает)...могу скинуть то, что имею сейчас…покавыряемся вместе…
Последний раз редактировалось Energy of Fire, 04.01.2012 в 23:10. |
#15
|
||||
|
||||
ну естественно, что если поставить хоткей на 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. |