![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | 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, но видно не получилось.
|
|
#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; |
|
#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. |