Overheadarmes/Codearmes Keyboard capturing

  • Moin,

    Um einem XY Problem vorzubeugen gleich vorweg das Ziel: Ich möchte ein GDI+ Ctrl basteln welches ähnlich zu einem Input-Ctrl arbeitet. (Texteingabe möglich). Außerdem soll es intern "keine" AutoIt-Ctrls verwenden, also kein "verstecktes" Ctrl das ausgelesen wird. Da das ganze angezeigt wird ist ein GUI vorhanden, RegisterMsg etc. funktioniert, GUIOnEventMode ist an. Die Tasten sollen nur gecaptured werden, wenn das GUI auch aktiv ist. Gedrückthalten von Tasten soll sich genauso verhalten wie man es vom InputCtrl gewohnt ist (also zunächst 1 Zeichen, dann kurze Pause, dann am laufenden Band neue Zeichen). Zu allem überfluss soll das ganze im Leerlauf möglichst wenig Performance brauchen, es wäre unschön, wenn ein Programm alleine 50% der Rechenzeit dafür aufwendet um ein InputCtrl zu verwalten.

    Anätze

    > IsPressed/Keyboardstate:

    - Sehr viel Code muss ausgeführt werden um anständig festzustellen was gedrückt wurde.

    - Kombinationen müssen von Hand ausgewertet werden (z.B. Shift + Taste)

    - Wird immer ausgeführt egal ob GUI aktiv ist, oder nicht.

    - Das Verhalten von "gedrückt halten einer Taste" muss manuell nachgebildet werden.

    > Hotkeys:

    - Unmengen Hotkeys müssen registriert werden.

    + Kombinationen wie Shift + Taste oder ähnliches ohne weitere Logik abrufbar.

    - Wird immer ausgeführt egal ob GUI aktiv ist, oder nicht.

    + Das Verhalten von "gedrückt halten einer Taste" wird unterstützt.

    > GUISetAccelerators:

    + Alle "Hotkeys" sind schnell und einfach initialisierbar (2D Array)

    + Kombinationen werden unterstützt.

    ? Belastet den GUIMessageLoop/EventLoop (wir sind im GUIOnEventMode, also werden die Accelerators -> Msgloop/Eventloop weitergeleitet) Keine ahnung "wie belastend" das ist, wenn da 150 Registrierungen drin sind.

    + Funktioniert nur wenn GUI aktiv.

    - Braucht "versteckte Ctrls" (DummyCtrl).

    ? Das Verhalten von "gedrückt halten einer Taste" wird unterstützt?

    > GUIRegisterMsg + Keymessages:

    + (glaube ich) Kombinationen werden unterstützt.
    + Belastet soweit ich weiß den Message/Eventloop nicht.

    ? Messages werden nur verschickt, wenn GUI aktiv?

    + (glaube ich) Man hat Zugriff auf zusätzliche Infos, weil lParam und wParam mehr als nur den Key der gedrückt wurde beinhaltet?

    ? Das Verhalten von "gedrückt halten einer Taste" wird unterstützt?

    Jetzt kommt die Frage: Was habe ich übersehen (gibt es noch weitere Wege?), und gibt es einen "richtigen" Weg bei der Sache?

    Einige Punkte habe ich mit Fragezeichen markiert, weil ich nicht genau weiß wie sich die Funktionen verhalten und weil ich nicht alles ausprobieren will.

    Hier braucht niemand irgendwelchen Code zu posten, alles was ich möchte ist (falls ihr etwas in der Art schonmal gemacht habt) eine Info wie man sowas richtig angeht.

    Meine Tendenz ist GUIRegisterMsg zu verwenden, aber vllt hat ja jemand hier mehr Erfahrung und kann mir einen Tipp geben.

    lg

    M

  • Mars 6. Oktober 2022 um 17:21

    Hat das Label [ offen ] hinzugefügt.
  • Es gibt ein Problem:

    Es eignet sich für eine vernünftige Performance eigentlich nur ein Hook (bzw. 2: Key- und WM). Was zum Problem führt, dass der User später keinen eigenen (gleichartigen) Hook in seinem Code einbauen kann, da dieser in der UDF bereits registriert ist. Vielleicht ist es schonmal jemandem gelungen, das in einen anderen Prozess oder Thread auszulagern und ggf. über IPC zu kommunizieren.

    Die Auswertung von Shift, Capslock, etc. ist auf den ersten Blick etwas schwierig, bis man es dann mal gemacht hat. Ich hatte mal eine derartige Auswertesoftware geschrieben zum Aufspüren von Benutzerfehlern an neuer Software. Wobei hier die erfassten Zeichen parallel in der Statusleiste angezeigt wurden, damit die Kontrolle nicht "heimlich" lief.

    Wenn ich am WE wieder daheim bin, kann ich das gern mal vorsuchen.

    Was du noch vergessen hast an Eigenschaften:

    Bewegen des Cursor im Ctrl mit

    - Pfeil li/re/auf/ab

    - Home/End

    - Kombinationen mit Shift/Ctrl und daraus resultierende Textmarkierung

    Diese Eigenschaften waren mein allererstes Programm - geschrieben in Turbopascal zur Ausführung in der Konsole (Nachbildung des Userinput von dbase) ;)

  • Was zum Problem führt, dass der User später keinen eigenen (gleichartigen) Hook in seinem Code einbauen kann, da dieser in der UDF bereits registriert ist.

    Bei der Window-Prozedur muss man doch nur zur bisherigen Prozedur springen, dann ist auch eine Verkettung möglich.

    Hier mal ein Beispiel:

  • Keyboardstate ist quasi "IsPressed" für alle Tasten gleichzeitig. Um das zu nutzen müsste man extrem oft Abfragen machen und quasi (hier 256) alle Keys andauernd abfragen um zu schauen ob etwas gedrückt wurde. Das ist für ein "paar wenige" Keys ggf eine gute Idee, aber wenn ich ca. 150 mögliche Keys überwachen muss, nur damit ab und zu einer davon gedrückt und erkannt wird, dann sind 99.9% der Abfragen nutzlos^^

    Damit auch schnelle Tastendrücke erfasst werden wäre man außerdem gezwungen mit hoher Frequenz zu prüfen (da die Events hier ungepuffert sind).

    Ich lass die Idee noch ein bisschen sacken, und dann wirds wahrscheinlich die Version von Oscar (Eigenes Window + Proc) mit sämtlichen Sachen die ich vergessen habe (wovon BugFix einige aufgezeigt hat). Wobei ich noch nicht ganz sicher bin, die WMs (ohne ein eigenes Window) sind auch verlockend, vermutlich weniger Komplexität in der Implementierung, dafür mehr Overhead. Allerdings ist laut der Hilfe WM_CHAR nicht immer nutzbar, wo das vermutlich am einfachsten wäre (auch in Bezug auf das Gedrückthalten von Tasten und Kombinationen von Tasten)...

    Da fällt mir direkt eine Frage ein: GUIRegisterMsg hat ja keinen Parameter für hWND. Hat ein Layered-Window dort einen eigenen Zugang (GuiSwitch und dann GUIRegisterMsg? Ich kenne mich damit leider nicht aus...), sodass ich z.B. WM_CHAR im Layered-Window registrieren kann (weil ich ja 100% sicher sein kann, dass ich kein Edit-Ctrl habe, also müsste WM_CHAR verfügbar sein)?


    Edit: Ich glaube ich bin da auf dem mentalen Holzweg. Kann es sein, dass die von RegisterMsg registrierten Funktionen mit den via SetWindowLong(..., WNDPROC, ...) registrierten Funktionen auf ein und dasselbe verweisen und diese Methode quasi die oben angesprochene GUIRegisterMsg Version "mit" HWND ist? Falls das so ist glaube ich es jetzt ansatzweise verstanden zu haben...

    Mensch, ein simples einfaches Texteingabefeld ist viel zu kompliziert... :rofl:

    lg

    M

  • Hey Mars!

    Ich dachte, dieses Thema schon einmal hier im Forum angesprochen zu haben, du hattest übrigens dazu auch ein Script gepostet... :P

    Cape-City
    8. Dezember 2016 um 20:33

    Dort werden mehrere Methoden vorgestellt.

  • Ich dachte, dieses Thema schon einmal hier im Forum angesprochen zu haben, du hattest übrigens dazu auch ein Script gepostet... :P

    Das ist der Beweis dafür, dass ich jetzt auch "zu den alten" gehöre. Ich habe selbst absolut keinen Überblick mehr über das was ich die letzten 10+ Jahre hier gepostet habe^^

    lg

    M

  • Mars 10. Oktober 2022 um 19:30

    Hat das Label von [ offen ] auf [ gelöst ] geändert.
  • Das ist der Beweis dafür, dass ich jetzt auch "zu den alten" gehöre.

    :rofl:

    ...werd du erst mal so alt, wie ich aussehe :rock:

    Jedenfalls schön, dass nicht alle Beiträge im Forennirvana verschwunden sind, etliche andere sind wohl für immer verloren....