Skróty MainMenu1 a nieaktywna forma

0

Cześć,

piszę sobie pewien program, który posiada komponent TMainMenu1. W tym menu są pozycje, które posiadają skróty klawiszowe (Shortcut). Moje pytanie brzmi - jak sprawić aby te skróty działały nawet gdy okno programu jest nieaktywne?

Pozdrawiam!

1

Skróty klawiszowe dla menu głównego i kontekstowych działają wyłącznie gdy okno jest odblokowane i zfokusowane – takie jest założenie i tak to musi działać. Jeśli z jakiegoś powodu potrzebujesz wywołać jakieś zdarzenie podczas gdy okno jest zablokowane (np. z powodu otwarcia okna dialogowego), to wywołaj je bezpośrednio, nie za pomocą hotkey'ów.

Nie próbuj zmieniać standardowego zachowania interfejsu, bo użytkownik na pewno nie będzie z tego powodu zadowolony. A najlepiej to napisz co konkretnie Twój program ma robić – wtedy się zobaczy czy problemem jest interfejs, czy jednak niepoprawna architektura.

0

Cześć, dzięki za odpowiedź :) Jeśli chodzi o mój problem, to tworzę automat do wykonywania prostych czynności i utworzyłam zadania, które dopisuję do listy zadań (np. kliknij w tym miejscu lewym klawiszem myszy). Te operacje działają na współrzędnych po których porusza się kursor i za pomocą skrótów klawiszowych dodaję sobie zadania do listy. Problem pojawia się wtedy, gdy wykonuję operację typu PPM->Nowy->Folder i moja aplikacja traci focus. Skrót klawiszowy nie działa i chciałabym wiedzieć w jaki sposób to naprawić.

Pozdrawiam!

0

OK problem rozwiązany - pomógł mi artykuł: https://www.swissdelphicenter.ch/en/showcode.php?id=147

Pozdrawiam!

0

W takim razie nie rozumiem do czego służą skróty klawiszowe i menu Twojego programu. Jeśli Twój ”clicker” ma wykonać jakieś zadanie (dodane do listy) to powinien przesuwać kursor i wywoływać zdarzenia myszy/klawiatury za pomocą SendInput lub od biedy mouse_event i keybd_event, dzięki czemu komunikaty zawsze będą dostarczane do aktywnego okna (i dostępne dla wszystkich innych programów nasłuchujących za pomocą hooków).

No nic, skoro masz już rozwiązanie i Cię zadowala to nie będę drążył tematu. ;)

0
furious programming napisał(a):

W takim razie nie rozumiem do czego służą skróty klawiszowe i menu Twojego programu. Jeśli Twój ”clicker” ma wykonać jakieś zadanie (dodane do listy) to powinien przesuwać kursor i wywoływać zdarzenia myszy/klawiatury za pomocą SendInput lub od biedy mouse_event i keybd_event, dzięki czemu komunikaty zawsze będą dostarczane do aktywnego okna (i dostępne dla wszystkich innych programów nasłuchujących za pomocą hooków).

No nic, skoro masz już rozwiązanie i Cię zadowala to nie będę drążył tematu. ;)

Moj program ma rejestrować w którym miejscu ktos chce kliknąć i zapisywać to miejsce do kolejki zadań i poki co to działa 😉
@robertz68 nie sądzę, ponieważ w onDestroy wszystko wraca do normy a mi te skróty nie są potrzebne podczas działania programu😉
Dzieki za odpowiedzi😘

0
Kaska1988 napisał(a):
furious programming napisał(a):

W takim razie nie rozumiem do czego służą skróty klawiszowe i menu Twojego programu. Jeśli Twój ”clicker” ma wykonać jakieś zadanie (dodane do listy) to powinien przesuwać kursor i wywoływać zdarzenia myszy/klawiatury za pomocą SendInput lub od biedy mouse_event i keybd_event, dzięki czemu komunikaty zawsze będą dostarczane do aktywnego okna (i dostępne dla wszystkich innych programów nasłuchujących za pomocą hooków).

No nic, skoro masz już rozwiązanie i Cię zadowala to nie będę drążył tematu. ;)

Moj program ma rejestrować w którym miejscu ktos chce kliknąć i zapisywać to miejsce do kolejki zadań i poki co to działa 😉

W miejscu czego?
Chodzi o pulpit Windows, dowolną aplikację Windows czy może całą Twoją aplikację, albo tez jakiś konkretny kontener w Twojej aplikacji (jak mazanie myszą po PaintBox)?

@robertz68 nie sądzę, ponieważ w onDestroy wszystko wraca do normy a mi te skróty nie są potrzebne podczas działania programu😉

Tego już w ogóle nie rozumiem...
To po co ci skróty klawiaturowe i ich obsługa, kiedy Twoja apka nie działa?

Jednak precyzja wypowiedzi będzie kluczowa dla jakości odpowiedzi.

0
Kaska1988 napisał(a):

Moj program ma rejestrować w którym miejscu ktos chce kliknąć i zapisywać to miejsce do kolejki zadań i poki co to działa 😉

Aha, czyli chodzi nie o symulowanie akcji użytkownika (odtwarzanie zaprogramowanej listy czynności), a o jej przygotowywanie. Użytkownik np. umeiszcza kursor w danym miejscu, wciska kombinację klawiszy i Twoja aplikacja dodaje akcję do listy czynności danego zadania.

Skoro tak to spoko – globalne hotkey'e nadają się do tego idealnie. Można też hookiem jakby co. ;)

0

Dokładnie, jest przygotowywana kolejka zadań do wykonania z parametrami do działania (np. właśnie współrzędne w które użytkownik chce kliknąć) :)

Tylko pojawił się kolejny problem, który nie bardzo rozumiem. Przygotowałam sobie skróty klawiszowe do zadań od F1 do F12. Wszystkie działają... poza F12. I nie wiem dlaczego F12 nie działa. Oto kod:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    id1, id2, id3, id4, id5, id6, id7, id8, id9, id10, id11, id12: Integer;
    procedure WMHotKey(var Msg: TWMHotKey); message WM_HOTKEY;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
   // HotKey F1
  id1 := GlobalAddAtom('HotKey1');
  RegisterHotKey(Handle, id1, 0{MOD_CONTROL}, VK_F1);

     // HotKey F2
  id2 := GlobalAddAtom('HotKey2');
  RegisterHotKey(Handle, id2, 0{MOD_ALT + MOD_SHIFT}, VK_F2{VK_A});

     // HotKey F3
  id3 := GlobalAddAtom('HotKey3');
  RegisterHotKey(Handle, id3, 0{MOD_WIN}, VK_F3{VK_A});

     // HotKey F4
  id4 := GlobalAddAtom('HotKey4');
  RegisterHotKey(Handle, id4, 0, VK_F4{VK_SNAPSHOT});

     // HotKey F5
  id5 := GlobalAddAtom('HotKey5');
  RegisterHotKey(Handle, id5, 0{MOD_CONTROL}, VK_F5);

     // HotKey F6
  id6 := GlobalAddAtom('HotKey6');
  RegisterHotKey(Handle, id6, 0{MOD_CONTROL}, VK_F6);

     // HotKey F7
  id7 := GlobalAddAtom('HotKey7');
  RegisterHotKey(Handle, id7, 0{MOD_CONTROL}, VK_F7);

  // HotKey F8
  id8 := GlobalAddAtom('HotKey8');
  RegisterHotKey(Handle, id8, 0{MOD_CONTROL}, VK_F8);

  // HotKey F9
  id9 := GlobalAddAtom('HotKey9');
  RegisterHotKey(Handle, id9, 0{MOD_CONTROL}, VK_F9);

  // HotKey F10
  id10 := GlobalAddAtom('HotKey10');
  RegisterHotKey(Handle, id10, 0{MOD_CONTROL}, VK_F10);

  // HotKey F11
  id11 := GlobalAddAtom('HotKey11');
  RegisterHotKey(Handle, id11, 0{MOD_CONTROL}, VK_F11);

  // HotKey F12
  id12 := GlobalAddAtom('HotKey12');
  RegisterHotKey(Handle, id12, 0{MOD_CONTROL}, VK_F12);
end;

//--------------- HOT KEYE ---------------------
procedure TForm1.WMHotKey(var Msg: TWMHotKey);
var
  MausPos: TPoint;
begin
  if Msg.HotKey = id1 then
  begin
    ShowMessage('F1');
  end;

  if Msg.HotKey = id2 then
  begin
    ShowMessage('F2');
  end;

  if Msg.HotKey = id3 then
  begin
    ShowMessage('F3');
  end;

  if Msg.HotKey = id4 then
  begin
     ShowMessage('F4');
  end;

  if Msg.HotKey = id5 then
  begin
     ShowMessage('F5');
  end;

  if Msg.HotKey = id6 then
  begin
     ShowMessage('F6');
  end;

  if Msg.HotKey = id7 then
  begin
     ShowMessage('F7');
  end;

  if Msg.HotKey = id8 then
  begin
     ShowMessage('F8');
  end;

  if Msg.HotKey = id9 then
  begin
     ShowMessage('F9');
  end;

  if Msg.HotKey = id10 then
  begin
     ShowMessage('F10');
  end;

  if Msg.HotKey = id11 then
  begin
     ShowMessage('F11');
  end;

  if Msg.HotKey = id12 then
  begin
     ShowMessage('F12');
  end;
end;
//----------------------------------

end.

Czy ktoś z Was widzi dlaczego klawisz F12 nie działa?

0

A ten klawisz przypadkiem nie koliduje ze skrótami IDE? U siebie – co prawda pod Lazarusem, ale to jeden pies – gdy program jest uruchomiony pod debuggerem, wciśnięcie klawisza F12 powoduje zatrzymanie pracy programu i przejście do debugowania assemblerka. Może w tym leży problem, bo błędu po stronie kodu nie widać. W razie czego sprawdź poza IDE czy będzie tak samo.

Poza tym, jeśli już używasz funkcji z systemowego API, to waliduj rezultaty wywołań. Ja wiem, że to pewnie PoC, ale warto o tym wspomnieć. Sprawdź czy hotkey F12 jest w ogóle rejestrowany – w razie sukcesu, rezultat będzie niezerowy.

0

Odpaliłam program poza IDE i niestety wciąż nie działa. Spróbuję jeszcze na innym komputerze, bo @wloochacz pisał że u niego działa. A co do reszty co napisałeś to nie wiem o czym mówisz :D Sorki ale nie jestem pro z Delphi :p

PS. Sprawdzałam też na innym komputerze - również nie działa.

0

Często ludzie w takich prostych programach jak auto kliker i innych podobynch korzystają z systemowych funkcji, które piszą do okien, które są na wierzchu.
Sendinput, sendmessage, vb_key.

Do czytania też są api jedno jest takie co czyta globalnie czasem do keyloggerów ludzie tworzą, getAsyncKeyState, możesz wypisywać w pętli każdy wcisnięty klawisz i zobaczyć czy jest rejestrowany, może coś event przechwytuje i nie podaje dalej, systemy i aplikacje muszę podać event dalej, ale można zatrzymać go i nikt więcej się nie dowie o tym.

Metoda wypisywania wszystkich klawiszy jest o tyle dobra, że jest to prawie jak debugowanie.

0
Kaska1988 napisał(a):

Odpaliłam program poza IDE i niestety wciąż nie działa. […] A co do reszty co napisałeś to nie wiem o czym mówisz :D Sorki ale nie jestem pro z Delphi :p

Chodzi o to, że funkcje z WinAPI zwracają jakieś wartości, które należy sprawdzać.

Ty radośnie wołasz RegisterHotKey, ale nie sprawdzasz co ta funkcja zwróciła, więc nie wiadomo czy skrót został zarejestrowany czy nie. A dokumentacja jasno podaje, że skrót może nie zostać zarejestrowany i wtedy funkcja zwróci wartość zerową (albo inaczej False). ;)

Spróbuj w ten sposób:

if not RegisterHotKey(Handle, id12, 0{MOD_CONTROL}, VK_F12) then
  ShowMessage('F12 cannot be registered');

i sprawdź czy wyskoczy komunikat błędu.

0

@wloochacz: myślałem że wszystko stało się jasne po odpowiedzi @furious programming i mojej aprobacie, ale odpowiem jeszcze raz - piszę program, który ma taki komponent memo. Do tego memo (za pomocą wspomnianych wcześniej skrótów) dodaję stringami zdefiniowane przeze mnie komendy. Komendy, np przy pomocy buttonów i po odpowiedniej analizie, będą później wykonywane. I teraz jak chcę kliknąć na pulpicie ikonkę to najeżdżam na nią kursorem myszy i klikam przykładowo F1 i bach - w memo pojawia się zapis w stylu kliknijLPM:50,200. I odpowiednia procedurka przeanalizuje ten zapis który powie jej, że ma kliknąć LPM w miejscu o współrzędnych 50, 200. I tak mam zaprogramowanych kilka czynności. Wszystko generalnie śmiga, tylko ten F12 bardzo mnie boli :(

0
furious programming napisał(a):
Kaska1988 napisał(a):

Odpaliłam program poza IDE i niestety wciąż nie działa. […] A co do reszty co napisałeś to nie wiem o czym mówisz :D Sorki ale nie jestem pro z Delphi :p

Chodzi o to, że funkcje z WinAPI zwracają jakieś wartości, które należy sprawdzać.

Ty radośnie wołasz RegisterHotKey, ale nie sprawdzasz co ta funkcja zwróciła, więc nie wiadomo czy skrót został zarejestrowany czy nie. A dokumentacja jasno podaje, że skrót może nie zostać zarejestrowany i wtedy funkcja zwróci wartość zerową (albo inaczej False). ;)

Spróbuj w ten sposób:

if not RegisterHotKey(Handle, id12, 0{MOD_CONTROL}, VK_F12) then
  ShowMessage('F12 cannot be registered');

i sprawdź czy wyskoczy komunikat błędu.

Uuu podziałało. Faktycznie nie zarejestrował F12 (pojawił się komunikat) :/ Co mogę teraz zrobić?

0
Kaska1988 napisał(a):

Faktycznie nie zarejestrował F12 (pojawił się komunikat) :/ Co mogę teraz zrobić?

Hmm… GetLastError? ;)

Najpierw pobierz numer błędu ww. funkcją, a następnie uzyskaj treść błędu za pomocą FormatMessage – tak jak piszą w dokumentacji. A jak już będziesz miała treść to sobie ją wyświetl używjąc ShowMessage.

0

Nie wiem czy dobrze robię, ale wpisując kod

ShowMessage(IntToStr(GetLastError));

Otrzymuję kod "0".

Natomiast kod

ShowMessage(SysErrorMessage(GetLastError));

podaje mi komunikat "Operacja ukończona pomyślnie"

1

Nie o to chodziło. W przypadku gdy RegisterHotKey zwróci 0/False (zależnie od implementacji importu funkcji), należy wywołać GetLastError i zapisać kod błędu do zmiennej liczbowej, następnie wywołać FormatMessage do konwersji kodu błędu na ciąg znaków, a ten wynikowy ciąg np. wyświetlić sobie za pomocą ShowMessage.

Albo zrobić tak jak w drugim przykładzie, ale po spełnieniu warunku:

if not RegisterHotKey(Handle, id12, 0{MOD_CONTROL}, VK_F12) then
  ShowMessage(SysErrorMessage(GetLastError()));

Mimo wszystko i tak sugeruję nie używać jednoklawiszowych hotkey'ów, bo istnieje zbyt duże prawdopodobieństwo, że aktywne okno może ten klawisz przetwarzać i wykonywać jakieś operacje, których nie chciałaś przeprowadzać. Skorzystaj choćby z jednego klawisza specjalnego, np. z Ctrl.

0

@furious programming dzięki za wyjaśnienie :) BTW zastosowałam Twój kod i dostałam komunikat "Klawisz dostępu jest już zarejestrowany". Będę próbować z CTRL ;)

1

OK z CTRL wszystko działa :) Dzięki i pozdrawiam!

1 użytkowników online, w tym zalogowanych: 0, gości: 1