Autor Beitrag
AndrewPoison
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17


Turbo Delphi 2006, Delphi 2009
BeitragVerfasst: So 14.09.08 10:46 
Hallo, nachdem ich mich ein wenig mit Hooks beschäftigt habe, kam nun am Ende ein Programm heraus das global wunderbar Tastenanschläge verfolgt. Das Problem: trotz Einbindung der CallNextHookEx-Funktion werden die Tasten, auf die ich reagiere, zwar abgefangen, aber nicht mehr weitergeleitet.

Hier der Code der Hook-DLL:

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:
59:
60:
61:
function KeyBoardProc(Code : integer;
                      wParam : integer;
                      lParam : integer): integer; stdcall;
//var
 // KeyUp : bool;
 {Remove comments for additional functionability
  IsAltPressed : bool;
  IsCtrlPressed : bool;
  IsShiftPressed : bool;
 }

begin
  result := 0;
  result := CallNextHookEx(lpHookRec^.TheHookHandle,Code,wParam,lParam);

  case Code of
    HC_ACTION : begin
     {We trap the keystrokes here}

     {Is this a key up message?}
     // KeyUp := ((lParam AND (1 shl 31)) <> 0);

    PostMessage(lpHookRec^.TheCtrlWinHandle,WM_KEYDOWN,wParam,lParam);
    PostMessage(lpHookRec^.TheCtrlWinHandle,WM_KEYUP,wParam,lParam);

    result := 0;

    (*Remove comments for additional functionability
     {Is the Alt key pressed}
      if ((lParam AND (1 shl 29)) <> 0) then begin
        IsAltPressed := TRUE;
      end else begin
        IsAltPressed := FALSE;
      end;

     {Is the Control key pressed}
      if ((GetKeyState(VK_CONTROL) AND (1 shl 15)) <> 0) then begin
        IsCtrlPressed := TRUE;
      end else begin
        IsCtrlPressed := FALSE;
      end;

     {if the Shift key pressed}
      if ((GetKeyState(VK_SHIFT) AND (1 shl 15)) <> 0) then begin
        IsShiftPressed := TRUE;
      end else begin
        IsShiftPressed := FALSE;
      end;
     *)


    end{HC_ACTION}
    HC_NOREMOVE : begin
      {This is a keystroke message, but the keystroke message}
      {has not been removed from the message queue, since an}
      {application has called PeekMessage() specifying PM_NOREMOVE}
      result := 0;
      exit;
    end;
  end{case code}
   {Call the next hook in the hook chain}
   result := CallNextHookEx(lpHookRec^.TheHookHandle,Code,wParam,lParam);
end;


und hier die Funktion, die beim Eintreffen des Events (korrekt) ausgelöst wird:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm1.WmHotkey(var Msg: TMessage);
begin
  if Msg.WParam = HK1 then OnSoftButtonsCB(1);
  if Msg.WParam = HK2 then OnSoftButtonsCB(2);
  if Msg.WParam = HK3 then OnSoftButtonsCB(4);
  if Msg.WParam = HK4 then OnSoftButtonsCB(8);
  {Msg.Result := 0;}
end;


Ich habe in dem DLL-Quelltext bereits die Funktion CallNextHookEx an verschiedenen Stellen angesetzt, so dass sie zumindest einmal durchlaufen werden muss, oder auch in der Handling-Funktion das Msg.Result auf 0 gesetzt (zum testen). Hat nicht so wirklich was gebracht. Wie gesagt, zuerst war ich der Ansicht, das es an der Hookchain liegt, allerdings glaube ich zunehmend auch das es daran nicht liegen kann: denn dann würden ja alle Tastenanschläge nicht weitergeleitet, nicht nur nicht diejenigen, auf die ich im Programm am Ende reagiere. Zur Eingabe, welcher "Hotkey" (eine einzelne Taste, z.B. "A" oder "7") verwendet werden soll um daraufhin eine Aktion durchzuführen, verwende ich eine THotKey-Komponente. Kann es sein, dass diese irgendwie den Fehler verursacht und die Tasten dann als Hotkey registriert und nicht mehr an andere Programme weiterleitet? Oder was ganz anderes?

Das Problem äußert sich halt z.B. darin, dass ich, wenn mein Programm läuft, keine der vier Tasten die als Hotkey definiert wurden in anderen Programmen mehr verwenden kann (z.B. erscheinen die Tasten dann nicht mehr hier beim schreiben des Posts, oder wenn ich die Taste einem anderen Hotkey zuweisen will klappts auch nicht).



/edit:

Problem hat sich gelöst. In einer anderen Unit war noch Quelltext von einem vorherigen Versuch enthalten, der mittel RegisterHotKey gearbeitet hat - und die Funktion scheint das ganze lahmgelegt zu haben. Nachdem ich den Part rausgeworfen hatte, läuft nun wieder alles. Liegt also weder an der Hookchain noch an der THotKey-Komponente. War einfach mein Fehler :/

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt
menticore
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 24

Win XP
D7 Enterprise
BeitragVerfasst: Do 18.09.08 22:14 
Titel: Ähnliches Problem
Hallo zusammen,

ich habe fast denselben Code, möchte aber das Gegenteil bewirken: Ich möchte eine programmierbare Tastatur entwerfen und Tasten abfangen. Wenn die Taste Rollen gedrückt wurde, sollen die Tasten abgefangen und verändert werden. Der globale Key-Hook funktioniert einwandfrei (von jemandem übernommen, daher die englischen Kommentare), dennoch werden die Tasten bsp. an Notepad weitergereicht. Ich habe mich schon mit diversen Tutorials auseinandergesetzt und gesucht, aber nichts dazu gefunden. Bin froh, dass der Hook erstmal läuft.

Aber wie kann ich die Tasten verändern? Wo liegt da bei mir der Denkfehler?

Quellcode ist unten...

Lieben Gruß,
menticore

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:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
library hooklib;

uses
  Windows, Messages, SysUtils;

type
  PHookRec = ^THookRec;
  THookRec = record
    AppHnd: Integer;
  end;

const
  memFile: PAnsiChar = 'Global7v9k'//Globale Memory-Datei

var
  Hooked: Boolean;
  hKeyHook, hMemFile, hApp: HWND;
  PHookRec1: PHookRec;

function KeyHookFunc(Code, VirtualKey, KeyStroke: Integer): LRESULT; stdcall;
var KeyboardState: TKeyBoardState;
begin
  Result := 0;
  if Code = HC_NOREMOVE then Exit;

  //Feststellen, ob die Rollen-Taste schon aktiv ist
  GetKeyboardState(KeyboardState);
  if KeyboardState[VK_SCROLL]=1 then begin
    Result := CallNextHookEx(hKeyHook, Code, 48, KeyStroke); //als Beispiel soll '0' geschickt werden
  end else begin
    Result := CallNextHookEx(hKeyHook, Code, VirtualKey, KeyStroke);
  end;

  //I moved the CallNextHookEx up here but if you want to block
  //or change any keys then move it back down
  if Code<0 then Exit;

  if Code = HC_ACTION then begin
    if ((KeyStroke and (1 shl 30)) <> 0then begin
      if not IsWindow(hApp) then begin
        //I moved the OpenFileMapping up here so it would not be opened
        //unless the app the DLL is attatched to gets some Key messages
        hMemFile  := OpenFileMapping(FILE_MAP_WRITE, False, memFile);
        PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 000);

        if PHookRec1<>nil then hApp := PHookRec1.AppHnd;
      end;

      //Die Tasten sollen nur an mein eigentliches Programm geschickt werden
      SendMessage(hApp, WM_USER + 1678, VirtualKey, KeyStroke);
    end;
  end;
end;
          
function StartHook(AppHandle: HWND): Byte; export;
begin
  Result := 0;

  //Wenn schon gehooked, dann nicht noch mal starten
  if Hooked then begin
    Result := 1;
    Exit;
  end;

  //KeyHook setzen
  hKeyHook := SetWindowsHookEx(WH_KEYBOARD, KeyHookFunc, hInstance, 0);
  if hKeyHook>0 then begin
    //you need to use a mapped file because this DLL attatches to every app
    //that gets windows messages when it's hooked, and you can't get info except
    //through a Globally avaiable Mapped file
    hMemFile := CreateFileMapping($FFFFFFFFnil, PAGE_READWRITE, 0, SizeOf(THookRec), memFile);
    PHookRec1 := MapViewOfFile(hMemFile, FILE_MAP_WRITE, 000);
    hApp := AppHandle;
    PHookRec1.AppHnd := AppHandle;
    //set the App handles to the mapped file
    Hooked := True;
  end else Result := 2//Hook konnte nicht gesetzt werden
end;

function StopHook: Boolean; export;
begin
  if PHookRec1<>nil then begin
    UnmapViewOfFile(PHookRec1);
    CloseHandle(hMemFile);
    PHookRec1 := nil;
  end;

  if Hooked then Result := UnhookWindowsHookEx(hKeyHook)
  else Result := True;
  Hooked := False;
end;

procedure EntryProc(dwReason: DWORD);
begin
  if dwReason=Dll_Process_Detach then begin
    if PHookRec1 <> nil then begin
      UnmapViewOfFile(PHookRec1);
      CloseHandle(hMemFile);
    end;
    UnhookWindowsHookEx(hKeyHook);
  end;
end;

exports
  StartHook,
  StopHook;

begin
  PHookRec1 := nil;
  Hooked := False;
  hKeyHook := 0;
  DLLProc := @EntryProc;
  EntryProc(Dll_Process_Attach);
end.
AndrewPoison Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 17


Turbo Delphi 2006, Delphi 2009
BeitragVerfasst: Do 18.09.08 23:23 
Meinen Hook hab ich von groups.google.com/gr...msg/ceb5818acd623a24

dort siehst du auch, wie man eine Taste verändern kann (die Sache, als er aus einem VK_LEFT ein VK_RIGHT macht). Hoffe damit konnte ich schon helfen ;)

Im Grunde macht er nichts anderes als abzufangen welche Taste gedrückt wurde (über wParam) und dann eine andere Message an dein Programm zu schicken.
Du rufst ja die CallNextHookEx-Funktion mit dem neuen Wert auf. Ob das überhaupt so funktionieren kann weiss ich nicht, aber ich denk mal ned, denn damit rufst du ja nur das nächste Hook-Handling auf, schickst die Message aber nicht an dein Programm - wie gesagt der verlinkte Code funktioniert zumindest. Natürlich müsstest du ihn halt auf deine Bedürfnisse anpassen.
menticore
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 24

Win XP
D7 Enterprise
BeitragVerfasst: Fr 19.09.08 14:40 
Danke dir.
Ich musste in der Funktion nur den Wert -1 zurückgeben und das wars auch schon.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
  GetKeyboardState(KeyboardState);
  if KeyboardState[VK_SCROLL]=1 then begin
    Result := -1;
    exit;
  end;

Nochmals danke und Gruß,
menticore