![]() |
Maus sperren während Tastatureingabe
Hallo.
Ich habe bei meinem Notebook folgendes Problem: Ich lege meine Handflächen während des Tippens meistens auf die Mitte der Tastatur, was bewirkt, dass ich mit den Handballen ständig auf das (meiner Meinung etwas zu große) Touchpad komme und ich somit während des Tippens ständig in das Textfeld klicke und mein Text dadurch ziemlich verunstaltet wird. Nach einer Recherche habe ich herausgefunden, dass viele Leute dieses Problem haben und dass es bis jetzt kein Tool dafür gibt. Die einzigste Workaround-Lösung ist, den Mauszeiger auf ein neutrales Element des Forms (im Browser z.B. die Lesezeichenleiste) zu setzen, bei der ein Klick keine Aktion und keinen Fokusverlust des Eingabefeldes bewirken kann. Das ist aber meiner Meinung nach unzureichend. Deswegen wollte ich mal versuchen, ein Tool zu entwickeln, dass die Maus während einer Tastatureingabe sperrt (Touchpad separat sperren ist ja unter Windows-Ebene nicht wirklich allgemein machbar) Ich stelle mir das so vor: 1. Das Ereignis einer Tastatureingabe wird auf Betriebssystemebene erfasst - im Notfall müsste man mit den Hook-DLLs von Keyloggern arbeiten, jedoch dann schlagen AntiViren-Programme zu, da sie ein Keylogger-Malware vermuten 2. Während der nächsten x-Sekunden wird die Maus in Sachen Bewegungen und Klicks gesperrt. (Eventuell könnte man noch einstellen, dass nur Klicks und Bewegungen nicht gesperrt werden) Wie kann ich das realisieren? - Man kann die letzte Eingabe mittels GetLastInputInfo() prüfen, jedoch wird dort auf Tastatur und Maus überprüft. Ich will jedoch nur den Zeitpunkt des letzten Tastenanschlags - Und wie man die Maus komplett oder nur partiell sperrt, weiß ich auch nicht. Man müsste eventuell eine Windows-Message abfangen und diese nach dem Erhalt als ungültig erklären, oder? Gruß blackdrake |
Re: Maus sperren während Tastatureingabe
viele Notebooks bieten die möglichkeit mit einer seperaten Taste oder in Verbindung mit FN das Touchpad zu deaktivieren. Falls diese Möglichkeit nicht vorhanden ist und man mit dem Touchpad nicht klar kommt ist eine weitere Möglichkeit das Touchpad im Gerätemanger zu deaktivieren und eine externe Maus anzuschließen.
|
Re: Maus sperren während Tastatureingabe
Hallo.
Ich möchte es wirklich gerne per Tool bewältigen. Mein Notebook besitzt eine [Fn]-Tastenkombination zur Deaktivierung des Touch-Felds. Das könnte ich machen, wenn ich sehr lange Texte tippe, aber für normale Benutzung wäre es nicht günstig, das Touch-Feld andauernd zu aktivieren und zu deaktivieren. Denn ich möchte das Touchfeld ja zwischen den Eingaben wirklich benutzen. Eine externe Maus ist auch nicht überall passend, besonders wenn es an Platz fehlt, man im Zug sitzt etc. Eine komplette deaktivierung des Touchfields wäre mir also nicht ganz so recht. Gruß blackdrake |
Re: Maus sperren während Tastatureingabe
Hallo.
In einem kleinen Testprogramm habe ich schon einen kleinen Fortschritt erwirkt. Wenn ein Button "Maus 3 Sekunden sperren" geklickt wird, wird die Maus innerhalb des Forms für 3 Sekunden gesperrt. Folgendes fehlt jetzt noch: 1. Der Hook muss die Maus Systemweit sperren 2. Ich muss noch herausfinden, wann die Tastatur zuletzt bedient wurde (aber NUR die Tastatur)
Delphi-Quellcode:
Gruß
var
HookID: THandle; function MouseProc(nCode: Integer; wParam, lParam: Longint): Longint; stdcall; var szClassName: array[0..255] of Char; begin case nCode < 0 of True: Result := CallNextHookEx(HookID, nCode, wParam, lParam) else case wParam of // Linke Maustaste sperren WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK: begin GetClassName(PMOUSEHOOKSTRUCT(lParam)^.HWND, szClassName, SizeOf(szClassName)); Result := HC_SKIP end else Result := CallNextHookEx(HookID, nCode, wParam, lParam); end; end; end; procedure DestroyHook; begin if HookID <> 0 then begin UnHookWindowsHookEx(HookID); end; end; procedure TForm1.FormDestroy(Sender: TObject); begin DestroyHook; end; procedure TForm1.sperre_maus_fuer_3_sekundenClick(Sender: TObject); begin // TODO: SYSTEM-GLOBAL DEN HOOK FÜR WM_MOUSE SETZEN! HookID := SetWindowsHookEx(WH_MOUSE, MouseProc, 0, GetCurrentThreadId()); timer1.enabled := true; end; procedure TForm1.Timer1Timer(Sender: TObject); begin DestroyHook; end; blackdrake |
Re: Maus sperren während Tastatureingabe
Zitat:
Zitat:
|
Re: Maus sperren während Tastatureingabe
Hallo,
Zitat:
Grüße, Uli |
Re: Maus sperren während Tastatureingabe
Ich glaube es geht hier um eine smarte Lösung für das Problem mit dem Touchpad.
Bei Outlook kann ich mit F9 meine emails abholen lassen. Aber das geht auch automatisch. Den Rechner kann ich ausschalten, wenn ich ihn nicht mehr brauche. Aber das geht mittlerweile auch automatisch (Standby, Ruhezustand). Bei meinem Auto kann ich alle Türen separat verschließen und öffnen. Die ZV macht das auf einen Schlag. Mit KeylessGo öffnet und schließt das Auto, wenn ich mich nähere oder entferne. Es geht nicht darum, dass man da manuell was machen kann, sondern um die smarte Automatik. Hier in der DP wurde schon mal darauf verlinkt ![]() cu Oliver |
Re: Maus sperren während Tastatureingabe
@Sir Rufo: :thumb:
|
Re: Maus sperren während Tastatureingabe
Hallo.
@Sir Rufo: Ja, genau so meine ich es. Im Endeffekt will ich das Tool auch veröffentlichen, da es in einigen Situationen bzw. bei einigen Anwendern wirklich sinnvoll ist. Die Klickfunktion des Touchpads zu Deaktivieren führt natürlich wieder zu einer gezwungenen Umstellung des Benutzers und ist außerdem nicht im Allgemeinen (bei allen Notebooks/Treibern) anwendbar. Und allgemeine Deaktivierungen bzw. per Fn-Tastenkombination sind nur bei längeren Schreibphasen sinnvoll. Ich habe jetzt mit dem Delphi-Treff-Tutorial folgende Anwendung mit DLL (ich möchte die DLL konventionell extern haben, nicht als Ressource) abgeleitet. Ich bekomme aber eine AV, sobald ich Button 1 oder 2 klicke. Ich weiß nicht, was da passiert :( Das DP Tutorial ist leider so kompliziert nonVCL geschrieben, dass ich es nur sehr schwer in VCL nachvollziehen/nachmachen kann. Ich denke, dass auch hier ein Problem bei der Transkription besteht. Hauptanwendung, die ein Keyboard-Ergeigniss erhalten soll
Delphi-Quellcode:
Die Hook-DLL, direkt übernommen
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); end; var Form1: TForm1; implementation {$R *.dfm} type TInstallHook = function(Hwnd: THandle): Boolean; stdcall; TUninstallHook = function: Boolean; stdcall; var InstallHooks: TInstallHook; UninstallHooks: TUninstallHook; lib: Cardinal; WM_MOUSEHOOKMSG: Cardinal = 0; WM_KEYBHOOKMSG: Cardinal = 0; const mousmsg='MouseHookMessage_Assarbad'; keybmsg='KeyboardHookMessage_Assarbad'; procedure TForm1.Button1Click(Sender: TObject); var h: hwnd; begin h := application.Handle; // ??? InstallHooks(h); // EXCEPTION WM_MOUSEHOOKMSG:=getprop(h,mousmsg); WM_KEYBHOOKMSG:=getprop(h,keybmsg); end; // TODO: Globale Keyboard Message abfragen (mit WM_KEY Message?) procedure TForm1.Button2Click(Sender: TObject); begin UnInstallHooks; // EXCEPTION WM_MOUSEHOOKMSG:=0; WM_KEYBHOOKMSG:=0; end; procedure TForm1.FormCreate(Sender: TObject); begin lib := LoadLibrary('hooks.dll'); if lib <> INVALID_HANDLE_VALUE then begin InstallHooks := GetProcAddress(lib, 'InstallHook'); UnInstallHooks := GetProcAddress(lib, 'UninstallHook'); end else begin ShowMessage('Hook could not be initialized. Please check "hooks.dll".'); Application.Terminate; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin FreeLibrary(lib); end; end.
Delphi-Quellcode:
library Hooks;
uses Windows, Messages; const mousmsg='MouseHookMessage_Assarbad'; keybmsg='KeyboardHookMessage_Assarbad'; var Mouse_HookHandle: Cardinal = 0; Keyboard_HookHandle: Cardinal = 0; WindowHandle: Cardinal = 0; WM_MOUSEHOOKMSG: Cardinal = 0; WM_KEYBHOOKMSG: Cardinal = 0; function KeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin //es ist ebenfalls moeglich die Bearbeitung an eine Bedingung zu knuepfen //it's possible to call CallNextHookEx conditional only. Result := CallNextHookEx(Keyboard_HookHandle, nCode, wParam, lParam); case nCode < 0 of TRUE: exit; //wenn code kleiner 0 wird nix gemacht //if code smaller 0 nothing has to be done FALSE: begin //Hier kann jetzt alles bearbeitet werden //Here one can work with the parameters setprop(WindowHandle, 'keyb_ncode', nCode); SendMessage(HWND_BROADCAST, WM_KEYBHOOKMSG, wParam, lParam); end; end; end; function MouseHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin //es ist ebenfalls moeglich die Bearbeitung an eine Bedingung zu knuepfen //it's possible to call CallNextHookEx conditional only. Result := CallNextHookEx(Mouse_HookHandle, nCode, wParam, lParam); case nCode < 0 of TRUE: exit; //wenn code kleiner 0 wird nix gemacht //if code smaller 0 nothing has to be done FALSE: begin //Hier kann jetzt alles bearbeitet werden //Here one can work with the parameters setprop(WindowHandle, 'mous_ncode', nCode); setprop(WindowHandle, 'mous_hwnd', PMOUSEHOOKSTRUCT(lParam)^.hwnd); setprop(WindowHandle, 'mous_hitt', PMOUSEHOOKSTRUCT(lParam)^.wHitTestCode); setprop(WindowHandle, 'mous_xpos', PMOUSEHOOKSTRUCT(lParam)^.pt.x); setprop(WindowHandle, 'mous_ypos', PMOUSEHOOKSTRUCT(lParam)^.pt.y); SendMessage(HWND_BROADCAST, WM_MOUSEHOOKMSG, wParam, lParam); end; end; end; function InstallHooks(Hwnd: Cardinal): Boolean; stdcall; var mouseh, keybh: boolean; begin keybh := false; mouseh := false; //Erstmal Hooks installieren //First install the hooks case Mouse_HookHandle of 0: begin Mouse_HookHandle := SetWindowsHookEx(WH_MOUSE, @MouseHookProc, HInstance, 0); SetProp(Hwnd,mousmsg,WM_MOUSEHOOKMSG); mouseh := true; end; end; case Keyboard_HookHandle of 0: begin Keyboard_HookHandle := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHookProc, HInstance, 0); SetProp(Hwnd,keybmsg,WM_KEYBHOOKMSG); keybh := true; end; end; //Uebergebenes Fensterhandle sichern //Save the given window handle WindowHandle := Hwnd; Result := keybh and mouseh; end; function UninstallHooks: Boolean; stdcall; var mouseh, keybh: boolean; begin //Hooks aus der Hookchain entfernen //Uninstall hook from hooks chain mouseh := UnhookWindowsHookEx(Mouse_HookHandle); keybh := UnhookWindowsHookEx(Keyboard_HookHandle); Mouse_HookHandle := 0; Keyboard_HookHandle := 0; Result := keybh and mouseh; if Result then WindowHandle := 0; end; exports //Installations- und Deinstallationsroutine exportieren //Export the installation and deinstallation routine InstallHooks, UninstallHooks; begin WM_MOUSEHOOKMSG:=RegisterWindowMessage(mousmsg); WM_KEYBHOOKMSG:=RegisterWindowMessage(keybmsg); end. |
Re: Maus sperren während Tastatureingabe
Die Anwort auf Deine ??? (Alfred Hitchcock :gruebel: ) aus Zeile 45 der Hauptanwendung findest Du m.E. in Zeile 80 des DLL-Codes:
Delphi-Quellcode:
cu
//Uebergebenes Fensterhandle sichern
//Save the given window handle WindowHandle := Hwnd; Oliver |
Re: Maus sperren während Tastatureingabe
Meinst du, es sollte so aussehen?
Delphi-Quellcode:
Wirft aber auch eine AV ab.
procedure TForm1.Button1Click(Sender: TObject);
var h: hwnd; begin h := WindowHandle; InstallHooks(h); // EXCEPTION WM_MOUSEHOOKMSG:=getprop(h,mousmsg); WM_KEYBHOOKMSG:=getprop(h,keybmsg); end; Das Problem ist, dass ich vom DP-Tutorial keine Belegung des hWnd's sehen konnte. Dort wird nämlich die API-Funktion mittels
Delphi-Quellcode:
aufgerufen, jedoch kann ich dann nicht wirklich die dlgfunc-Parameter, die auch die hWnd enthält, sehen...
DialogBoxParam(HInstance, MAKEINTRESOURCE(DIALOG1), 0, @dlgfunc, 0);
In sofern weiß ich nicht genau, welches Handle überhaupt verlangt ist... |
Re: Maus sperren während Tastatureingabe
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var h: hwnd; begin h := Form1.Handle; // <--- Eher so ... InstallHooks(h); // EXCEPTION WM_MOUSEHOOKMSG:=getprop(h,mousmsg); WM_KEYBHOOKMSG:=getprop(h,keybmsg); end; |
Re: Maus sperren während Tastatureingabe
Hallo.
Funktioniert leider immer noch nicht. Ich denke, die AV kommt aufgrund einer ungültigen DLL-Interaktion. Wäre nur das Handle falsch, würde das wahrscheinlich nicht zu einer AV führen. Hast du eine Idee? Gruß blackdrake |
Re: Maus sperren während Tastatureingabe
Hallo,
Der Fehler lag beim GetProcAddress, da bei den 2 Tutorials einmal von *Hook und einmal von *Hooks die Rede war. Ich habe jetzt einen fast funktionierenden Code, jedoch gibt es noch 2 Dinge, mit denen ich Probleme habe: 1. Die Strg-Taste wird auch als Taste angesehen ... hier muss sich dringend noch eine Allgemeine Lösung finden, weil Strg+Maustaste ja legitim sind 2. Das Sperren der Maustaste funktioniert nicht. Eigentlich dachte ich, es genüge, einfach das WndProc, das man verwerfen möchte, einfach nicht mehr per inherited weiterzureichen, doch es funktioniert einfach nicht. Zum Testen: Ich habe während die Anwendung im Hintergrund läuft in einem Notepad etwas eingetippt. Das Fenster im Hintergrund zeigt als Debugausgabe "Gesperrt". Während der Eingabe klicke ich in meinen geschriebenen Text hinein. Nach der Eingabe werden die Textstellen markiert, weil scheinbar die Mausereignisse doch noch im Eingabepuffer waren und nicht durch die Hook-DLL verworfen wurden. Code (DLL hooks.dll in den oberen Posts):
Delphi-Quellcode:
Gruß
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Label1: TLabel; debug_tmr: TTimer; Label2: TLabel; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure debug_tmrTimer(Sender: TObject); procedure FormShow(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); public last_keyboard_input: DWORD; procedure WndProc(var Message:TMessage); override; end; var Form1: TForm1; implementation {$R *.dfm} type TInstallHook = function(Hwnd: THandle): Boolean; stdcall; TUninstallHook = function: Boolean; stdcall; var InstallHooks: TInstallHook; UninstallHooks: TUninstallHook; lib: Cardinal; WM_MOUSEHOOKMSG: Cardinal = 0; WM_KEYBHOOKMSG: Cardinal = 0; const mousmsg='MouseHookMessage_Assarbad'; keybmsg='KeyboardHookMessage_Assarbad'; const sperrdauer = 3000; // 3 Sekunden, später Variabel // ToDo: Programm total lahm, wenn Delphi gestartet ist // (auch außerhalb des Debuggers) ? procedure TForm1.WndProc(var Message:TMessage); var difference: DWORD; begin if Message.Msg = WM_KEYBHOOKMSG then begin inherited WndProc(Message); // Eine Taste wurde gedrückt, wir merken uns den Zeitpunkt last_keyboard_input := GetTickCount(); // ToDo: Tasten wie Strg dürfen nicht mitgezählt werden, // da diese in Kombination mit der Maustaste OK sind! end else if Message.Msg = WM_MOUSEHOOKMSG then begin difference := GetTickCount() - last_keyboard_input; if (difference <= sperrdauer) and ((Message.wParam = WM_LBUTTONDBLCLK) or (Message.wParam = WM_LBUTTONDOWN) or (Message.wParam = WM_LBUTTONUP)) then begin // Ereignis verwerfen, da linke Maustaste innerhalb // der Sperrzeit gedrückt wurde // Something ToDo ? // Debug: Zeigen, dass etwas gesperrt wurde label2.Caption := 'Sperrung: ' + IntToStr(GetTickCount()); end else begin // Sonstiges Mausereignis bzw. Mausklick außerhalb // der Sperrzeit erlauben inherited WndProc(Message); end; end else begin // Andere Ereignisse durchlassen inherited WndProc(Message); end; end; procedure TForm1.debug_tmrTimer(Sender: TObject); var difference: DWORD; begin difference := GetTickCount() - last_keyboard_input; if difference > sperrdauer then begin label1.Caption := 'Freigegeben'; end else begin label1.Caption := 'Gesperrt'; end; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin UnInstallHooks; WM_MOUSEHOOKMSG:=0; WM_KEYBHOOKMSG:=0; end; procedure TForm1.FormCreate(Sender: TObject); begin lib := LoadLibrary('hooks.dll'); if lib <> INVALID_HANDLE_VALUE then begin InstallHooks := GetProcAddress(lib, 'InstallHooks'); UnInstallHooks := GetProcAddress(lib, 'UninstallHooks'); end else begin ShowMessage('Hook could not be initialized. Please check "hooks.dll".'); Application.Terminate; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin FreeLibrary(lib); end; procedure TForm1.FormShow(Sender: TObject); begin InstallHooks(Handle); WM_MOUSEHOOKMSG:=getprop(Handle, mousmsg); WM_KEYBHOOKMSG:=getprop(Handle, keybmsg); end; end. blackdrake |
Re: Maus sperren während Tastatureingabe
Zitat:
Zitat:
a) ist sie sehr weit weg vom Mousepad b) wird diese beim Schreiben von Text eher selten benötigt c) wird beim Schreiben von Text innerhalb der Sperrzeit eine weitere Taste gedrückt. Nur mit der STRG-Taste ist es schwierig einen Text zu verfassen :mrgreen: Zitat:
Aber das weiß ich adhoc auch nicht ... vielleicht habe ich nachher, wenn der planet wieder scheint, etwas zeit, mir das mal anzusehen ;-) Zitat:
cu Oliver |
Re: Maus sperren während Tastatureingabe
Hallo.
Ich weiß nicht, wie ich hier die Maus-Aktion rückgängig machen soll.
Delphi-Quellcode:
Dieses Konstrukt der DLL sieht nicht aus wie eine WndProc-Schleife, bei der man eine nicht gebrauchte Message einfach nicht per inherited weiterreicht...
function MouseHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin //es ist ebenfalls moeglich die Bearbeitung an eine Bedingung zu knuepfen //it's possible to call CallNextHookEx conditional only. Result := CallNextHookEx(Mouse_HookHandle, nCode, wParam, lParam); case nCode < 0 of TRUE: exit; //wenn code kleiner 0 wird nix gemacht //if code smaller 0 nothing has to be done FALSE: begin //Hier kann jetzt alles bearbeitet werden //Here one can work with the parameters setprop(WindowHandle, 'mous_ncode', nCode); setprop(WindowHandle, 'mous_hwnd', PMOUSEHOOKSTRUCT(lParam)^.hwnd); setprop(WindowHandle, 'mous_hitt', PMOUSEHOOKSTRUCT(lParam)^.wHitTestCode); setprop(WindowHandle, 'mous_xpos', PMOUSEHOOKSTRUCT(lParam)^.pt.x); setprop(WindowHandle, 'mous_ypos', PMOUSEHOOKSTRUCT(lParam)^.pt.y); SendMessage(HWND_BROADCAST, WM_MOUSEHOOKMSG, wParam, lParam); end; end; end; Ich glaube, dass ich nach SendMessage() das result neutralisieren muss, wenn ich das Ereignis verwerfen möchte. Das Problem: Die Message WM_MOUSEHOOKMSG müsste dann ja auch noch ein Ergebnis zurückliefern, in dem steht, ob das WM_MOUSE* Ereignis gelöscht wird oder nicht. Gibt es denn keine bessere Lösung, bei der ich das Maus-Links-Klick-Ereignis löschen kann, ohne die DLL unnötig zu erweitern? Gruß blackdrake |
Re: Maus sperren während Tastatureingabe
Vielleicht ist der Maushook dann der falsche Ansatz?! Es gibt auch Messagehooks :-)
|
Re: Maus sperren während Tastatureingabe
Och nö, wie soll denn das jetzt gehen?
Ich habe mal versucht, ![]() Außerdem wird nirgends beschrieben, WIE dieser Left-Mouse-Hook (im Link Middle-Mouse-Hook) nun angewandt wird, also dass der Hook sich tatsächlich als Ereignis auf meine Anwendung auswirkt. Folgendes scheint nicht zu funktionieren:
Delphi-Quellcode:
Kann mir bitte jemand helfen? Ich möchte ein systemglobales Maus-Hook mit der möglichkeit, das Mausereignis innerhalb meiner Anwendung (also nicht in der DLL) rückgängig zu machen.
public
procedure Test(var msg: TWMNCLButtonDown); message WM_NCLBUTTONDOWN; end; procedure RunHook; stdcall; external 'left_mouse_hook.dll' name 'RunHook'; procedure KillHook; stdcall; external 'left_mouse_hook.dll' name 'KillHook'; procedure TForm1.Test(var msg: TWMNCLButtonDown); begin Button1.Caption := IntToStr(GetTickCount()); end; procedure TForm1.FormCreate(Sender: TObject); begin RunHook; end; procedure TForm1.FormDestroy(Sender: TObject); begin KillHook; end; |
Re: Maus sperren während Tastatureingabe
Erstelle eine MMF mit einem eindeutigen Namen (am besten ein GUID). In diese schreibst du von der Anwendung aus das Fensterhandle deines Forms. In der DLL öffnest du die MMF und schickst deine eigene Nachricht an das Fenster, am besten eine mit RegisterWindowMessage registrierte. Dieses Senden sollte unbedingt mit SendMessageTimeout erfolgen und mit den Flags SMTO_ABORTIFHUNG sowie SMTO_BLOCK! Alles andere kann dazu führen, dass das System nicht mehr zu gebrauchen ist. Dein Formular kann mit dem Nachrichten-Ergebnis mitteilen, ob der Hook die alte Nachricht weiterleiten oder verändern soll.
|
Re: Maus sperren während Tastatureingabe
Oh je, sowas kompliziertes habe ich noch nicht gehört :pale: Geht denn das nicht auch einfacher oder irgendwie als existierenden Code, den man umändern kann?
|
Re: Maus sperren während Tastatureingabe
Ich habe gerade wieder etwas mit der Mouse+Keyboard-Hook-DLL probiert.
Kann man das auch irgendwie so machen, dass auf die Hook-Message mit "0" geantwortet wird, wenn das Mausereignis gelöscht werden soll?
Delphi-Quellcode:
In der DLL:
procedure TForm1.WndProc(var Message:TMessage);
var difference: DWORD; begin if Message.Msg = WM_KEYBHOOKMSG then begin inherited WndProc(Message); // Eine Taste wurde gedrückt, wir merken uns den Zeitpunkt last_keyboard_input := GetTickCount(); // ToDo: Tasten wie Strg dürfen nicht mitgezählt werden, // da diese in Kombination mit der Maustaste OK sind! end else if Message.Msg = WM_MOUSEHOOKMSG then begin difference := GetTickCount() - last_keyboard_input; if (difference <= sperrdauer) and ((Message.wParam = WM_LBUTTONDBLCLK) or (Message.wParam = WM_LBUTTONDOWN) or (Message.wParam = WM_LBUTTONUP)) then begin // Ereignis verwerfen, da linke Maustaste innerhalb // der Sperrzeit gedrückt wurde // Something ToDo ? Message.Result := 0; // Debug: Zeigen, dass etwas gesperrt wurde label2.Caption := 'Sperrung: ' + IntToStr(GetTickCount()); end else begin // Sonstiges Mausereignis bzw. Mausklick außerhalb // der Sperrzeit erlauben inherited WndProc(Message); end; end else begin // Andere Ereignisse durchlassen inherited WndProc(Message); end; end;
Delphi-Quellcode:
Würde soetwas funktionieren oder ist es der falsche Weg? Ich komme mit der Windows API einfach nicht klar...
function MouseHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin Result := CallNextHookEx(Mouse_HookHandle, nCode, wParam, lParam); case nCode < 0 of TRUE: exit; FALSE: begin setprop(WindowHandle, 'mous_ncode', nCode); setprop(WindowHandle, 'mous_hwnd', PMOUSEHOOKSTRUCT(lParam)^.hwnd); setprop(WindowHandle, 'mous_hitt', PMOUSEHOOKSTRUCT(lParam)^.wHitTestCode); setprop(WindowHandle, 'mous_xpos', PMOUSEHOOKSTRUCT(lParam)^.pt.x); setprop(WindowHandle, 'mous_ypos', PMOUSEHOOKSTRUCT(lParam)^.pt.y); if SendMessage(HWND_BROADCAST, WM_MOUSEHOOKMSG, wParam, lParam) = 0 then begin result := WM_NULL; // Funktioniert das? end; end; end; end; |
Re: Maus sperren während Tastatureingabe
Wenn du deine Nachricht an HWND_BROADCAST schickst, kannst du kein Ergebnis erhalten, da die Nachricht an alle Top-Level-Fenster geschickt wird. Deshalb habe ich auch die MMF vorgeschlagen.
Zum Verwerfen der Nachricht zitiere ich mal die MSDN Library: Zitat:
|
Re: Maus sperren während Tastatureingabe
Könntest du bzgl. des MMF ein kleines Beispiel posten, sofern es keine Umstände macht?
|
Re: Maus sperren während Tastatureingabe
Kein Thema.
Delphi-Quellcode:
//Anwendung
hMapping := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, 4, 'The mapping of the black drake'); pView := MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, 0); PCardinal(pView)^ := Handle; //Aufräumen bei Programmende UnmapViewOfFile(pView); CloseHandle(hMapping); //In der DLL hMapping := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'THe mapping of the black drake'); pView := MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); TargetHandle := PCardinal(pView)^; //Aufräumarbeiten bei DLL_PROCESS_DETACH UnmapViewOfFile(pView); CloseHandle(hMapping); |
Re: Maus sperren während Tastatureingabe
Hallo.
Danke für den Code. Ich werde versuchen, damit den Übertragungsweg zu realisieren. |
Re: Maus sperren während Tastatureingabe
Der MMF Übertragungsweg funktioniert nun.
Ein Problem habe ich noch bei der Verwerfung des Mausklicks. Ich verstehe nicht ganz, wie das getan werden soll. WM_NULL ist ja scheinbar falsch, aber was soll dann als Result zurückgegeben werden? Ausschnitt Anwendung:
Delphi-Quellcode:
Ausschnitt DLL:
procedure TForm1.WndProc(var Message:TMessage);
var difference: DWORD; begin if Message.Msg = WM_ANYKEY_PRESSED then begin inherited WndProc(Message); // Eine Taste wurde gedrückt, wir merken uns den Zeitpunkt last_keyboard_input := GetTickCount(); end else if Message.Msg = WM_LMOUSECLK_CONFIRM then begin difference := GetTickCount() - last_keyboard_input; if (difference <= sperrdauer) then begin // Ereignis verwerfen, da linke Maustaste innerhalb // der Sperrzeit gedrückt wurde // Der DLL melden, dass das Hook die Mausnachricht verwerfen soll. Message.Result := 10; // Debug: Zeigen, dass etwas gesperrt wurde label2.Caption := 'Sperrung: ' + IntToStr(GetTickCount()); end else begin // Sonstiges Mausereignis bzw. Mausklick außerhalb // der Sperrzeit erlauben inherited WndProc(Message); end; end else begin // Andere Ereignisse durchlassen inherited WndProc(Message); end; end;
Delphi-Quellcode:
Die "10" ist die Rückantwort, die sagen soll, dass das Mausereignis verworfen werden soll.
function MouseHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var res: Cardinal; begin Result := CallNextHookEx(Mouse_HookHandle, nCode, wParam, lParam); case nCode < 0 of TRUE: exit; FALSE: begin // Handelt es sich um einen linken Mausklick? if (wParam = WM_LBUTTONDBLCLK) or (wParam = WM_LBUTTONDOWN) or (wParam = WM_LBUTTONUP) then begin // Dann Anwendung fragen, ob das OK ist SendMessageTimeOut(TargetHandle, WM_LMOUSECLK_CONFIRM, wParam, lParam, SMTO_ABORTIFHUNG or SMTO_BLOCK, MsgTimeOut, res); if res = 10 then begin // Mausklick verwerfen Result := WM_NULL; // ToDo: Funktioniert nicht... end; end; end; end; end; |
Re: Maus sperren während Tastatureingabe
Das Problem ist wohl, dass du CallNextHook() in jedem Fall aufrufst.
Delphi-Quellcode:
Das einzige was ich jetzt nicht weiss ist, ob und wann nCode jemals <0 wird. Result ist in dem Fall dann undefiniert, und müsste mit einem konstanten Wert vorbelegt werden, der dazu führt dass der Wert von nCode ebenfalls Einfluss darauf hat ob das Ereignis durchkommt oder nicht. Man müsste nur mal schauen unter welchen Bedingungen nCode<0 auftritt.
function MouseHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var res: Cardinal; begin case nCode < 0 of TRUE: exit; FALSE: begin // Handelt es sich um einen linken Mausklick? if (wParam = WM_LBUTTONDBLCLK) or (wParam = WM_LBUTTONDOWN) or (wParam = WM_LBUTTONUP) then begin // Dann Anwendung fragen, ob das OK ist SendMessageTimeOut(TargetHandle, WM_LMOUSECLK_CONFIRM, wParam, lParam, SMTO_ABORTIFHUNG or SMTO_BLOCK, MsgTimeOut, res); if res = 10 then // Mausklick verwerfen Result := 1 // Irgend ein nicht-null Wert. So hab ich es zumindest auch schon mal gemacht ;) else Result := CallNextHookEx(Mouse_HookHandle, nCode, wParam, lParam); end; end; end; end; end; |
Re: Maus sperren während Tastatureingabe
Hallo.
Danke für den Tipp, ich werde es später zu Hause gleich ausprobieren. Ein Verständnisproblem habe ich aber noch: Du sagst, CallNextHookEx() soll nicht aufgerufen werden, wenn ich mein Ereignis verwerfen will, deswegen hast du CallNextHookEx() in die If-Abfrage reingepackt. Klingt logisch. Was ist aber für den Fall dass nCode<0 ist (was das auch immer bedeuten soll)? In meinem vorherigen Code, den ich von Delphi-Treff übernommen habe, wurde CallNextHookEx() auch aufgerufen wenn nCode<0 wäre - war das unrichtig bzw. unnötig? Gruß blackdrake |
Re: Maus sperren während Tastatureingabe
Deswegen mein letzter Absatz ;). Ich hatte bei meinem Programm die Abfrage vor, also ausserhalb der nCode-Bedingung, da ich selbst noch in der DLL auf das Event reagieren wollte, aber sonst keiner mehr. Das Problem bei dir ist nun, dass du deine Hostanwendung erst fragen musst ob zu ignorieren ist oder nicht. Wenn du es so biegen kannst dass du es in der DLL direkt entscheiden kannst, dürfte es kein Problem sein das ganze aus dem nCode-Abschnitt zu nehmen. (So langsam wäre es echt interessant zu wissen was nCode angibt. Das msdn fand ich da imho nicht recht hilfreich.)
Bei meinem Programm kann man auch im Host das Ignorieren ab- und anschalten, was mir ein Flag in einem gemeinsamen MMF setzt. Damit entscheide ich dann in der DLL ob geblockt wird oder nicht ohne jedes Mal nachfragen zu müssen. Evtl. wäre das eine Alternative zum Message-Frage-Antwort-Spiel für dich. |
Re: Maus sperren während Tastatureingabe
Hi Blackdrage,
ich hatte auch dieses Touchpad Problem und habe es dann mittels automatischem sperren der Maus gelöst, evtl reicht dir das ja auch Siehe ![]() |
Re: Maus sperren während Tastatureingabe
Zitat:
Dann ist die sperre ja wieder raus und er klickt fröhlich weiter wild rum. |
Re: Maus sperren während Tastatureingabe
also bei mir hat das Tool wunderbar geholfen.
Denn meistens kommt man tatsächlich nur ganz kurz drauf, und wenn ihm das Tool nicht hilft kann er sich ja immernoch eins selbst basteln ;). Ich bin halt der Meinung, wieso selber Proggen wenns eine Freeware auch tut. |
Re: Maus sperren während Tastatureingabe
Zitat:
Ich finde den Ansatz von blackdrake genau richtig, obwohl in beiden Versionen jeweils eine Annahme zugrunde liegt: - blackdrake: Nach dem letzten Tastendruck (ausgenommen STRG) kann ich 3 Sekunden mein Touchpad vergessen - Corpsman: "Denn meistens kommt man tatsächlich nur ganz kurz drauf," Da der Ansatz von blackdrake immer so funtioniert (funzen soll) kann sich der Anwender drauf einstellen oder am Zeitintervall etwas drehen. Bei deinem Ansatz kann es völlig unkontrolliert und vom Anwender nicht wirklich nachvollziehber (sonst bräuchten wir so ein Programm eh nicht) trotzdem zu ungewollten Reaktionen kommen, die das Prgramm ja eigentlich verhindern soll. Es ist etwas anderes, ob ich eine Funktionsweise erwarte oder ob diese mich überrascht. Und eine Lösung die von Konzept her 100% funktioniert ist dann besser als eine die im Konzept Schwächen hat. Es geht dabei nicht um die Umsetzung - das kann ich nicht beurteilen - aber den Ansatz. cu Oliver |
Re: Maus sperren während Tastatureingabe
@ sir,
Ist ja nett das du hier deine Meinung dagegen vorträgst, die Argumente will ich auch gar nicht bewerten, jedoch wärs nett wenn du einen Lösungsansatz postest, sonst hast du hier nur "heise Luft" verblasen ... |
Re: Maus sperren während Tastatureingabe
|
Re: Maus sperren während Tastatureingabe
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo.
Danke für eure Beiträge. Das Tool habe ich nicht ausprobiert, da es mir zu statisch vorkommt. Außerdem bin ich ja gerade dabei, ein eigenes kleines Tool zu schreiben, bei dem ich außerdem noch einiges über die WinAPI dazulerne. Ich habe jetzt folgendes gemacht: - Die DLL prüft nun intern, ob die Maustaste erlaubt ist oder nicht, deswegen ist jetzt kein "Frage-Antwort-Spiel" mit der Host-Applikation mehr nötig. - Die DLL übergibt der Host-Applikation folgende Messages, die z.B. für grafische Ereignisse/Hinweise verwendet werden können: * WM_LMB_LOCKED -- die linke Maustaste ist ab jetzt gesperrt (Host-App soll Systemzeiger in crNo verändern) * Nach 3 Sekunden kommt dann automatisch: WM_LMB_UNLOCKED -- die linke Maustaste ist ab jetzt wieder freigeschaltet (Host-App soll den Systemzeiger wiederherstellen) * WM_LMB_BLOCKED -- eine linke Maustaste wurde innerhalb der Sperrzeit gedrückt. Das Ereignis wurde geblockt! (z.B. Sound-Ereignis abspielen) Aber es existieren folgende Bugs, bei denen ich nicht weiterkomme: 1. Host-App: Der Mauszeiger wird nicht nach crNo mittels SetSystemCursor() innerhalb der WndProc() geändert! Außerhalb der WndProc() funktioniert es seltsamerweiße!
Delphi-Quellcode:
2. DLL: Die Kontrolle, ob eine Strg-Taste gedrückt ist, funktioniert nicht!
procedure TForm1.WndProc(var Message:TMessage);
begin if Message.Msg = WM_LMB_BLOCKED then begin label2.Caption := 'WM_LMB_BLOCKED ' + IntToStr(GetTickCount()); end else if Message.Msg = WM_LMB_LOCKED then begin label1.Caption := 'WM_LMB_LOCKED'; // BUG 1!!! Mauszeiger verändern funktioniert nicht cursor_backup := GetCursor; SetSystemCursor(Screen.Cursors[crNo], OCR_NO); end else if Message.Msg = WM_LMB_UNLOCKED then begin label1.Caption := 'WM_LMB_UNLOCKED ' + IntToStr(GetTickCount()); SetSystemCursor(cursor_backup, OCR_NORMAL); end; inherited WndProc(Message); end; 3. DLL: Der (einmalige) Timer, der nach WM_LMB_LOCKED (neu)gestartet wird und nach 3 Sekunden zu WM_LMB_UNLOCKED führen soll, funktioniert nicht! Er funktioniert nur, wenn man innerhalb der Host-Anwendung Tasten drückt. Tippt man in Notepad etwas ein, dann ist der Timer gleich 0.
Delphi-Quellcode:
Könnt ihr mit bitte weiterhelfen? Ich habe bei diesen 3 Bugs keine Lösung erzielen können.
var
lock_interval: Integer; // wird bei dem DLL-Start gesetzt bzw. mit einer externen DLL-Funktion aktualisiert last_timer: Cardinal; procedure timerevent; var res: Cardinal; begin // Es soll ein einmaliger Timer sein KillTimer(0, last_timer); last_timer := 0; SendMessageTimeOut(TargetHandle, WM_LMB_UNLOCKED, 0, 0, SMTO_ABORTIFHUNG or SMTO_BLOCK, MsgTimeOut, res); end; function KeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var res: Cardinal; begin Result := CallNextHookEx(Keyboard_HookHandle, nCode, wParam, lParam); case nCode < 0 of TRUE: exit; FALSE: begin // BUG 2!!! VK_CONTROL-Kontrolle funktioniert nicht! // Strg+Maustaste ist legitim für Mehrfachselektion if GetKeyState(VK_CONTROL) = 0 then begin last_keyboard_input := GetTickCount(); SendMessageTimeOut(TargetHandle, WM_LMB_LOCKED, 0, 0, SMTO_ABORTIFHUNG or SMTO_BLOCK, MsgTimeOut, res); // Jetzt: 3 Sekunden warten und dann WM_LMB_UNLOCKED senden, ggf. vorherigen Timer zurücksetzen // BUG 3!!! Dieser Timer funktioniert nur, wenn man in der Anwendung // was tippt. Tippt man z.B. im Notepad, hat der Timer // ein Interval von 0 statt 3000. // Den vorherigen Timer zurücksetzen if last_timer <> 0 then KillTimer(0, last_timer); last_timer := SetTimer(0, IDC_TIMER1, lock_interval, @timerevent); end; end; end; end; Wenn ihr nochwas im Projekt findet, schreibt mir bitte Vorschläge! Gruß Daniel Marschall |
Re: Maus sperren während Tastatureingabe
Mit SetTimer und KillTimer bist du in einer DLL zu unflexibel. Wenn du für den ersten Parameter Null einsetzt, spielst du Vabanque. Du gehst nämlich davon aus, dass alle Applikationen, die die DLL geladen haben, eine Nachrichtenschleife haben. Wie die Nachrichten-Weitergabe bei einem Null-Handle passiert, ist mir selbst noch nicht ganz klar.
Ich würde auf Waitable Timer umsteigen. Erstelle dir einen neuen Thread, der nur auf den Timer warten und beim Ablaufen die Unblocked-Nachricht versendet. Schau dir dazu mal ![]() ![]() Aber zuletzt noch etwas anderes: Ich hielt die vorige Lösung für besser, in der ein zentrales Programm steuert, ob Mausereignisse blockiert werden. Andernfalls musst du nämlich eine ganze Menge Daten in die MMF schreiben, damit die DLLs immer synchron arbeiten und nicht eine Instanz Ereignisse durchlässt und eine andere blockiert. |
Re: Maus sperren während Tastatureingabe
Zitat:
Zitat:
|
Re: Maus sperren während Tastatureingabe
Zitat:
Hast du das Problem mit der abgestürzten Anwendung wirklich getestet?. Zitat:
|
Re: Maus sperren während Tastatureingabe
Mehrere DLL-Instanzen? Bedeutet das etwa folgendes?
- Host-Anwendung Project1.exe startet StartLocker() der DLL (dort wird der Hook gestartet und Variablen gesetzt). - Sobald ich in Notepad etwas tippe, öffnet Notepad nochmal die DLL? Woher weiß Notepad aber, dass in meiner DLL StartLocker() gestartet werden muss? Dann wäre die Verwaltung über die zentrale Host-Applikation über die eindeutige GUID doch besser. :| |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:33 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz