Autor Beitrag
dYnAm1c
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16



BeitragVerfasst: So 03.07.11 03:59 
Hallo,
ich programmiere im moment ein Programm mit Systemweiten Hotkeys für ein Spiel.
Da das Spiel anscheinend Direct Input verwendet und die Hotkeys deswegen nicht Ingame funktionieren,
musste ich statt registerHotKey die Funktion "SetWindowsHookEx" und "WH_KEYBOARD_LL"
nehmen und einen Low Level Hook programmieren.

Im moment sieht das ganze so aus:

ausblenden volle Höhe Delphi-Quelltext
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:
type
  tagKBDLLHOOKSTRUCT = record
    vkCode: DWORD;
    scanCode: DWORD;
    flags: DWORD;
    time: DWORD;
    dwExtraInfo: DWORD;
  end;
  TKbdDLLHookStruct = tagKBDLLHOOKSTRUCT;
  PKbdDLLHookStruct = ^TKbdDLLHookStruct;

var
  Form1: TForm1;
  HookHandle: Cardinal = 0;
  WindowHandle: Cardinal = 0;


function InstallHook(Hwnd: Cardinal): Boolean; stdcall;
begin
  Result := False;
  if HookHandle = 0 then begin
    HookHandle := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyboardProc, hInstance, 0);
    WindowHandle := Hwnd;
    Result := HookHandle <> 0;
  end;
end;


function LowLevelKeyboardProc(nCode: Integer; wParam: wParam; lParam: lParam): LRESULT; stdcall;
begin
if (Form1.Visible = True) AND (Form3.Visible = False) then begin
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD7) then
     Form1.Button1.Click;
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD8) then
     Form1.Button2.Click;
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD4) then
     Form1.Button3.Click;
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD5) then
     Form1.Button4.Click;
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD1) then
     Form1.Button5.Click;
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD2) then
     Form1.Button6.Click;
    Result := CallNextHookEx(HookHandle, nCode, wParam, lParam);
    end;
if (Form1.Visible = False) AND (Form3.Visible = True) then begin
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD7) then
     Form3.Button1.Click;
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD9) then
     Form3.Button2.Click;
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD5) then
     Form3.Button3.Click;
    if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = VK_NUMPAD2) then
     Form3.Button4.Click;
    Result := CallNextHookEx(HookHandle, nCode, wParam, lParam);

end;
end;


Wie man sieht benutze ich für die Hotkeys im moment die Nummernfeld Tasten.
Allerdings würde ich vom User die Tasten gerne selber festlegen wollen, allerdings weiß
ich nicht wie ich da vorgehen soll, wär also nett wenn jemand was wüsste :)


MfG
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: So 03.07.11 09:11 
Nimm doch statt den keycodes einfach eine variable. Es gibt da auch so eine Komponente für, wo man hotkeys eingeben kann als User.
Aber hier würde das dann zunächst so aussehen:
ausblenden Delphi-Quelltext
1:
2:
if (nCode >= 0and (wParam = WM_KEYDOWN) and (PKbdDLLHookStruct(lParam)^.vkCode = Hotkey1) then
     Form1.Button1.Click;


mit hotkey1 als globaler Variable.
Aber Systemweit wird das so eh nicht klappen. Die Callback-Funktion Lowlevelkeyboardproc muss aus einer dll kommen, und du brauchst IPC. Lies dazu dieses Tutorial.
Deine Callback liegt ja in deiner Exe, der Hook wird aber in den anderen Prozessen ausgeführt. Dort ist deine Funktion aber garnicht vorhanden.
mfg Boldar
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.07.11 10:11 
user profile iconBoldar hat folgendes geschrieben Zum zitierten Posting springen:
Aber Systemweit wird das so eh nicht klappen. Die Callback-Funktion Lowlevelkeyboardproc muss aus einer dll kommen, und du brauchst IPC.
Das stimmt nicht... Dass sich dieser Mythos immer noch hartnäckig hält... Probiere es einfach mal aus... :roll:

Andere Hooktypen (wie die Nicht-Lowlevel-Verson) müssen in der Tat in einer DLL untergebracht werden. Denn diese werden z.B. im Fall von WH_KEYBOARD und WH_MOUSE vom Fenstermanager aufgerufen, da hier erst die Messages an die Zielanwendung abgefangen werden. Daher braucht man eine DLL-Funktion, da es ein anderer Prozess ist.

Die Lowlevel-Hooks für Maus und Tastatur hingegen werden vom System selbst quasi auf Treiberebene verwaltet. Deshalb ist hier keine DLL nötig.
dYnAm1c Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16



BeitragVerfasst: So 03.07.11 11:48 
Das mit der Komponente für HotKeys zu machen habe ich mir auch schon überlegt, nur mit welchem
Variablentypen soll ich die denn abspeichern?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.07.11 12:11 
Das ist natürlich eine ganz schwierige Frage, wenn du in dem Record ja siehst, dass vkCode als DWORD deklariert ist...
dYnAm1c Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16



BeitragVerfasst: So 03.07.11 13:29 
Ok das klappt schonmal. Nurnoch eine kleine Frage, kann ich in die HotKey Komponente noch weitere HotKeys eintragen?
Im moment sind da ja nur die vorgegebenen drin. Kobinationen aus CTRL + 1 sind da z.B. gar nicht drin und Numpad Tasten ebenfalls nicht.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.07.11 14:07 
Du kannst dir auch ein Edit nehmen und das selbst implementieren was du brauchst.
dYnAm1c Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16



BeitragVerfasst: So 03.07.11 14:16 
Also kann ich bei der HotKey Komponente keine weiteren Einträge hinzufügen?
Und wenn das nicht geht könnte ich statt Edit aber auch einfach eine ComboBox nehmen?
Ist ja praktisch das gleiche wie Edit nur das man schon vorgegebene Auswahlen kann.

Edit: Also ich hab mal ein bisschen rumprobiert und erstmal ist das dabei rausgekommen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
private
  { Private declarations }
    const
      VK_1 = $31;
      VK_CONTROL = $11;

var
  Form2: TForm2;
  HotKeyNR1: DWORD;

procedure TForm2.Button1Click(Sender: TObject);
begin

case ComboBox1.ItemIndex of
0: HotKeyNR1 := VK_1;

end;


Das ganze funktioniert auch, allerdings wollte ich ja auch HotKeys welche sich z.B. aus zwei Tasten zusammensetzten. Ist das in einem Hook überhaupt möglich? Meine Variante die ich probiert hat klappt auf jedenfall nicht:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm2.Button1Click(Sender: TObject);
begin

case ComboBox1.ItemIndex of
0: HotKeyNR1 := VK_CONTROL + VK_1;

end;
dYnAm1c Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16



BeitragVerfasst: Mo 04.07.11 21:29 
/push

*nochmal frag*
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 04.07.11 23:24 
Du kannst nicht zwei Tasten exakt gleichzeitig herunterdrücken. Es kommt immer einer der Tastendrücke zuerst an...

Wenn also Z und X als Tastenkombination gedrückt wird, bekommst du zuerst WM_KEYDOWN (das steht in wParam drin, siehe Doku) für Z, dann WM_KEYDOWN für X, dann je einmal WM_KEYUP für die beiden Tasten...
dYnAm1c Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16



BeitragVerfasst: Di 05.07.11 01:49 
Und wie genau kann ich das dann anders umsetzen?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 05.07.11 10:35 
Wie meinst du das? Du bekommst die Tastenaktionen doch alle. :nixweiss:

Du musst dir doch nur speichern, dass die erste herunter gedrückt wurde. Und wenn die zweite vor dem Loslassen der ersten auch gedrückt wurde, hast du die Kombination.