Hallo,
ich habe beim Erstellen eines Tastaturhooks drei Probleme:
Das erste ist mehr eine Frage als ein Problem: Jedes Tastaturereignis bekomme ich doppelt geliefert, d. h. meine Hookprozedur wird immer zweimal mit völlig identischen Parametern aufgerufen - für jedes Taste drücken zweimal keydown (wenn man die taste gedrückt hält auch mehr), und für jedes Loslassen zweimal Keyup. Weiss jemand warum das so ist, und ob das in allen Windows Versionen so passiert, ich verwende Windows 7 32bit - im Prinzip ist es kein wirkliches Problem, weil ich den zweiten Aufruf ganz einfach an Callnexthookex weiterreiche (muss/soll ich das überhaupt?) und sonst ignoriere, aber ich hätte gerne gewusst, was da los ist.
Das zweite: getShiftLockState kommt mir wie ein Glücksspiel vor. Um einen Shiftlocktastendruck zu simulieren, möchte ich, falls die Taste gerade gedrückt ist ein Keyup und dann ein keydown event generieren oder falls sie gearde nicht gedrückt ist, erst keydown und dann keyup. Der Testausgabe entnehme ich, dass der von getkeystate geliefert Wert manchmal mit dem wirklichen Tastenstatus übereinstimmt und oft auch nicht. Was könnte da falsch sein?
Delphi-Quellcode:
procedure getShiftLockState;
var x: byte;
begin
x:=GetKeyState(VK_CAPITAL);
ShftLockUp := x and 128 <> 0;
ShftLockActive := odd(x);
end;
procedure DoShiftLock;
// Aktiviere shift-lock:
// je nach aktueller Position der Taste
// drücken-loslassen oder loslassen-drücken
const
ev: array [boolean] of longInt = (0, KEYEVENTF_KEYUP);
begin
getShiftLockState;
(*$IFDEF TEST*)
if ShftLockUp
then Msg ('DoShiftLock down-up')
else Msg ('DoShiftLock up-down');
(*$ENDIF*)
keybd_event (VK_CAPITAL, 0, ev[not ShftLockUp], 0);
keybd_event (VK_CAPITAL, 0, ev[ShftLockUp], 0);
end;
Das dritte Problem: Ich habe mir naiverweise vorgestellt, dass wenn ich in meiner Hookprozedur zuerst DoShiftLock aufrufe und danach callnexthookex aufrufe, entsprechend zuerst der Shiftlock-Status umgeschaltet werden müsste und danach der echte Tastendruck mit bereits umgeschaltetem Shiftlock Status im Eingabefeld ankommen sollte, tatsächlich ist es aber umgekehrt, erst kommt die - deshalb falsch umgeschaltete - Taste an und danach wird erst der shiftlock Status umgeschaltet. Es hat den Anschein, als würde Windows ein neus Tastaturereignis erst starten, wenn das vorige komplett abgearbeitet ist? Aber woher weiss das Windows System, wann eine Tastaturereignis fertig abgearbeitet ist? Eine Hookprozedur könnte doch auch ein Tastaturereignis schlucken und gar nicht mittels callnexthookex weiterleiten, dann wäre die Tastatur doch auf ewig blockiert?
Delphi-Quellcode:
begin // function KeyboardHookProc
DoBefore; // hier drin erfolgt der Aufruf von DoShiftLock
(*$IFDEF TEST*)
IF NOT DOPPELT // Doppelte Tastaturereignisse auch bei Testausgabe nicht berücksichtigen, wegen Problem 1
THEN BEGIN Msgadd(' Hook '+chr(key));
if (pb^[4] and 128)<>0 then MsgAdd ('Up');
end;
(*$ENDIF*)
Result := CallNextHookEx(HookHandle, nCode, key, lParam);
DoAfter;
end;
edit: zu den Fragen zu meinem Problem 3 bin ich eben draufgekommen, dass das Unsinn ist. Windows erkennt ja das Ende meiner Tastaturbehandlung nicht daran, dass ich CallNextHookEx aufrufe, sondern daran, dass meine Behandlungsroutine fertig ist und zur aufrufenden Routine zurückkehrt. Das Problem mit der Asynchronizität ist aber leider noch lästiger, als ich geglaubt habe: wie ich eben feststellen musste, können, wenn man schnell schreibt, sogar normale Tasten die künstlich erzeugten Tastaturereignisse, die auf Grund eines früher erfolgten Tastendrucks in der Hookroutine zu diesem früheren Tastendruck erzeugt werden, "überholen". Das heisst, ich drücke rasch hintereinander die Tasten Taste1 und Taste2. In der Tastaturbehandlungsroutine von Taste1 erzeuge ich z.B. Shift-Lock. Dieses künstlich erzeugte Tastaturereignis ShiftLock taucht aber nicht nur erst nach dem Ereignis Taste1 auf, was schon lästig genug wäre, sondern u.U. sogar erst nach dem Tastaturereignis Taste2.